For #21732 - Adds inactive tabs survey on disable + telemetry

upstream-sync
codrut.topliceanu 3 years ago committed by mergify[bot]
parent 6d62aed35f
commit bba787e87e

@ -1720,6 +1720,38 @@ preferences:
notification_emails:
- android-probes@mozilla.com
expires: "2022-11-01"
inactive_tabs_survey_opened:
type: event
description: >
A survey for asking the user why she intends to turn off the
inactive tabs feature is shown.
bugs:
- https://github.com/mozilla-mobile/fenix/issues/21732
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/21862#issuecomment-949598042
data_sensitivity:
- interaction
notification_emails:
- android-probes@mozilla.com
expires: "2022-02-01"
turn_off_inactive_tabs_survey:
type: event
description: >
The user has disabled inactive tabs feature and responded
to our request for feedback.
extra_keys:
feedback:
description: |
The user's feedback regarding inactive tabs feature.
bugs:
- https://github.com/mozilla-mobile/fenix/issues/21732
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/21862#issuecomment-946977614
data_sensitivity:
- interaction
notification_emails:
- android-probes@mozilla.com
expires: "2022-02-01"
search.default_engine:
code:

@ -20,6 +20,7 @@ import org.mozilla.fenix.GleanMetrics.Events
import org.mozilla.fenix.GleanMetrics.Logins
import org.mozilla.fenix.GleanMetrics.Onboarding
import org.mozilla.fenix.GleanMetrics.Pocket
import org.mozilla.fenix.GleanMetrics.Preferences
import org.mozilla.fenix.GleanMetrics.ProgressiveWebApp
import org.mozilla.fenix.GleanMetrics.SearchShortcuts
import org.mozilla.fenix.GleanMetrics.TabsTray
@ -203,6 +204,12 @@ sealed class Event {
data class TabsTrayCloseInactiveTab(val amountClosed: Int = 1) : Event()
object TabsTrayOpenInactiveTab : Event()
object InactiveTabsSurveyOpened : Event()
data class InactiveTabsOffSurvey(val feedback: String) : Event() {
override val extras: Map<Preferences.turnOffInactiveTabsSurveyKeys, String>
get() = mapOf(Preferences.turnOffInactiveTabsSurveyKeys.feedback to feedback.lowercase(Locale.ROOT))
}
object ProgressiveWebAppOpenFromHomescreenTap : Event()
object ProgressiveWebAppInstallAsShortcut : Event()

@ -37,6 +37,7 @@ import org.mozilla.fenix.GleanMetrics.Metrics
import org.mozilla.fenix.GleanMetrics.Onboarding
import org.mozilla.fenix.GleanMetrics.Pings
import org.mozilla.fenix.GleanMetrics.Pocket
import org.mozilla.fenix.GleanMetrics.Preferences
import org.mozilla.fenix.GleanMetrics.ProgressiveWebApp
import org.mozilla.fenix.GleanMetrics.ReaderMode
import org.mozilla.fenix.GleanMetrics.RecentBookmarks
@ -626,6 +627,13 @@ private val Event.wrapper: EventWrapper<*>?
is Event.TabsTrayOpenInactiveTab -> EventWrapper<NoExtraKeys>(
{ TabsTray.openInactiveTab.add() }
)
is Event.InactiveTabsSurveyOpened -> EventWrapper<NoExtraKeys>(
{ Preferences.inactiveTabsSurveyOpened.record(it) }
)
is Event.InactiveTabsOffSurvey -> EventWrapper(
{ Preferences.turnOffInactiveTabsSurvey.record(it) },
{ Preferences.turnOffInactiveTabsSurveyKeys.valueOf(it) }
)
is Event.AutoPlaySettingVisited -> EventWrapper<NoExtraKeys>(
{ Autoplay.visitedSetting.record(it) }
)

@ -4,8 +4,12 @@
package org.mozilla.fenix.settings
import android.content.res.Configuration
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.RadioButton
import androidx.preference.PreferenceCategory
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreference
@ -14,14 +18,18 @@ import org.mozilla.fenix.R
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.metrics.Event.TabViewSettingChanged
import org.mozilla.fenix.components.metrics.Event.TabViewSettingChanged.Type
import org.mozilla.fenix.databinding.SurveyInactiveTabsDisableBinding
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.metrics
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.ext.showToolbar
import org.mozilla.fenix.utils.view.addToRadioGroup
import java.util.Locale
/**
* Lets the user customize auto closing tabs.
*/
@Suppress("TooManyFunctions")
class TabsSettingsFragment : PreferenceFragmentCompat() {
private lateinit var listRadioButton: RadioButtonPreference
private lateinit var gridRadioButton: RadioButtonPreference
@ -32,6 +40,9 @@ class TabsSettingsFragment : PreferenceFragmentCompat() {
private lateinit var inactiveTabsCategory: PreferenceCategory
private lateinit var inactiveTabs: SwitchPreference
private lateinit var searchTermTabGroups: SwitchPreference
private val shouldShowInactiveTabsTurnOffSurvey
get() = requireContext().settings().isTelemetryEnabled &&
requireContext().settings().shouldShowInactiveTabsTurnOffSurvey
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.tabs_preferences, rootKey)
@ -45,6 +56,7 @@ class TabsSettingsFragment : PreferenceFragmentCompat() {
override fun onResume() {
super.onResume()
showToolbar(getString(R.string.preferences_tabs))
setupPreferences()
}
@ -68,8 +80,25 @@ class TabsSettingsFragment : PreferenceFragmentCompat() {
radioOneDay = requirePreference(R.string.pref_key_close_tabs_after_one_day)
inactiveTabs = requirePreference<SwitchPreference>(R.string.pref_key_inactive_tabs).also {
it.isChecked = it.context.settings().inactiveTabsAreEnabled
it.onPreferenceChangeListener = SharedPreferenceUpdater()
it.isChecked = requireContext().settings().inactiveTabsAreEnabled
it.setOnPreferenceChangeListener { preference, newValue ->
if (shouldShowInactiveTabsTurnOffSurvey && newValue == false) {
// The first time the user tries to disable the feature show a little survey for her motives.
val inactiveTabsSurveyBinding = SurveyInactiveTabsDisableBinding.inflate(
LayoutInflater.from(context),
view as ViewGroup,
true
)
setupSurvey(inactiveTabsSurveyBinding)
requireContext().metrics.track(Event.InactiveTabsSurveyOpened)
// Don't update the preference as a direct action of user tapping the switch.
// Only disable the feature after the user selects an option in the survey or expressly closes it.
false
} else {
SharedPreferenceUpdater().onPreferenceChange(preference, newValue)
}
}
}
inactiveTabsCategory = requirePreference<PreferenceCategory>(R.string.pref_key_inactive_tabs_category).also {
@ -88,6 +117,66 @@ class TabsSettingsFragment : PreferenceFragmentCompat() {
setupRadioGroups()
}
private fun setupSurvey(inactiveTabsSurveyBinding: SurveyInactiveTabsDisableBinding) {
inactiveTabsSurveyBinding.closeSurvey.setOnClickListener {
finishInactiveTabsSurvey(inactiveTabsSurveyBinding)
// Register that user closed this survey without picking any option.
requireContext().metrics.track(
Event.InactiveTabsOffSurvey("none")
)
}
// A map is needed to help retrieve the correct string on SEND.
// These values are also sent to Glean which will truncate anything over 100 UTF8 characters.
val radioButtonsMap: Map<Int, Int> = mapOf(
R.id.rb_do_not_understand to R.string.inactive_tabs_survey_do_not_understand,
R.id.rb_do_it_myself to R.string.inactive_tabs_survey_do_it_myself,
R.id.rb_time_too_long to R.string.inactive_tabs_survey_time_too_long_option,
R.id.rb_time_too_short to R.string.inactive_tabs_survey_time_too_short_option,
)
// Sets the Radio buttons' text
radioButtonsMap.forEach {
inactiveTabsSurveyBinding.surveyGroup.findViewById<RadioButton>(it.key)?.text =
requireContext().getText(it.value)
}
inactiveTabsSurveyBinding.sendButton.setOnClickListener {
val checkedRadioButtonId = inactiveTabsSurveyBinding.surveyGroup.checkedRadioButtonId
// If no option has been selected the button does not need to do anything.
if (checkedRadioButtonId != -1) {
finishInactiveTabsSurvey(inactiveTabsSurveyBinding)
// Using the stringId of the selected option an event is sent using English.
radioButtonsMap[checkedRadioButtonId]?.let { stringId ->
requireContext().metrics.track(
Event.InactiveTabsOffSurvey(getDefaultString(stringId))
)
}
}
}
}
/**
* Set the inactive tabs survey completed and the feature disabled.
*/
private fun finishInactiveTabsSurvey(inactiveTabsSurveyBinding: SurveyInactiveTabsDisableBinding) {
inactiveTabsSurveyBinding.surveyContainer.visibility = View.GONE
requireContext().settings().shouldShowInactiveTabsTurnOffSurvey = false
requireContext().settings().inactiveTabsAreEnabled = false
requirePreference<SwitchPreference>(R.string.pref_key_inactive_tabs).isChecked = false
}
/**
* Get the "en-US" string value for the indicated [resourceId].
*/
private fun getDefaultString(resourceId: Int): String {
val config = Configuration(requireContext().resources.configuration)
config.setLocale(Locale.ENGLISH)
return requireContext().createConfigurationContext(config).getText(resourceId).toString()
}
private fun setupRadioGroups() {
addToRadioGroup(
listRadioButton,

@ -867,6 +867,14 @@ class Settings(private val appContext: Context) : PreferencesHolder {
default = true
)
/**
* Should we display a feedback request to the user when he turns off the Inactive Tabs feature
*/
var shouldShowInactiveTabsTurnOffSurvey by booleanPreference(
appContext.getPreferenceKey(R.string.pref_key_should_show_inactive_tabs_turn_off_survey),
default = true
)
fun getSitePermissionsPhoneFeatureAction(
feature: PhoneFeature,
default: Action = Action.ASK_TO_ALLOW

@ -0,0 +1,114 @@
<?xml version="1.0" encoding="utf-8"?><!-- 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/. -->
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/survey_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:background="@drawable/onboarding_card_background_light">
<TextView
android:id="@+id/survey_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="18dp"
android:layout_marginEnd="16dp"
android:text="@string/inactive_tabs_survey_header"
android:textAppearance="@style/Body12TextStyle"
android:textColor="#592ACB"
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintEnd_toStartOf="@+id/close_survey"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/survey_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:text="@string/inactive_tabs_survey_content"
android:textAppearance="@style/Body14TextStyle"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/survey_title" />
<RadioGroup
android:id="@+id/survey_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="18dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="18dp"
app:layout_constraintBottom_toTopOf="@+id/send_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/survey_subtitle"
app:layout_constraintVertical_bias="0.0">
<RadioButton
android:id="@+id/rb_do_not_understand"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/Body14TextStyle" />
<RadioButton
android:id="@+id/rb_do_it_myself"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/Body14TextStyle" />
<RadioButton
android:id="@+id/rb_time_too_long"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/Body14TextStyle" />
<RadioButton
android:id="@+id/rb_time_too_short"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/Body14TextStyle" />
</RadioGroup>
<ImageButton
android:id="@+id/close_survey"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?selectableItemBackgroundBorderless"
android:contentDescription="@string/inactive_tabs_survey_close_button_content_description"
android:paddingStart="18dp"
android:paddingTop="20dp"
android:paddingEnd="18dp"
android:paddingBottom="20dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_close" />
<Button
android:id="@+id/send_button"
style="@style/MetropolisButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:background="@color/toolbar_menu_transparent"
android:text="@string/inactive_tabs_survey_send_button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -358,4 +358,7 @@
<!-- App Spinners colors -->
<color name="spinner_selected_item">#1415141A</color>
<!-- Toolbar menu icon colors -->
<color name="toolbar_menu_transparent">@android:color/transparent</color>
</resources>

@ -212,6 +212,9 @@
<!-- A value of `true` means the jump back in onboarding popup has not been shown yet -->
<string name="pref_key_should_show_jump_back_in_tabs_popup" translatable="false">pref_key_should_show_jump_back_in_tabs_popup</string>
<!-- A value of `true` means the inactive tabs turn off - survey hasn't been shown yet-->
<string name="pref_key_should_show_inactive_tabs_turn_off_survey" translatable="false">pref_key_should_show_inactive_tabs_turn_off_survey</string>
<string name="pref_key_migrating_from_fenix_nightly_tip" translatable="false">pref_key_migrating_from_fenix_nightly_tip</string>
<string name="pref_key_migrating_from_firefox_nightly_tip" translatable="false">pref_key_migrating_from_firefox_nightly_tip</string>

@ -1966,19 +1966,21 @@
<!-- Inactive tabs survey -->
<!-- Header text for the inactive tabs survey asking for feedback to improve the inactive tabs feature. -->
<string name="inactive_tabs_survey_header" tools:ignore="UnusedResources">Please help us to improve</string>
<string name="inactive_tabs_survey_header">Help improve Firefox</string>
<!-- Content text for the inactive tabs survey asking the primary survey feedback question. -->
<string name="inactive_tabs_survey_content" tools:ignore="UnusedResources">Why did you disable inactive tabs?</string>
<string name="inactive_tabs_survey_content">Why did you disable inactive tabs?</string>
<!-- One of the feedback option that can be selected as a responses to the inactive tabs survey question. -->
<string name="inactive_tabs_survey_not_interested_option" tools:ignore="UnusedResources">Not interested in the feature</string>
<string name="inactive_tabs_survey_do_not_understand">I dont understand how it works</string>
<!-- One of the feedback option that can be selected as a responses to the inactive tabs survey question. -->
<string name="inactive_tabs_survey_time_too_long_option" tools:ignore="UnusedResources">Time to inactive is too long</string>
<string name="inactive_tabs_survey_do_it_myself">I like to clear out old tabs myself</string>
<!-- One of the feedback option that can be selected as a responses to the inactive tabs survey question. -->
<string name="inactive_tabs_survey_time_too_short_option" tools:ignore="UnusedResources">Time to inactive is too short</string>
<string name="inactive_tabs_survey_time_too_long_option">The two-week time period is too long</string>
<!-- One of the feedback option that can be selected as a responses to the inactive tabs survey question. -->
<string name="inactive_tabs_survey_time_too_short_option">The two-week time period is too short</string>
<!-- Confirmation button text to submit the feedback for the inactive tabs survey. -->
<string name="inactive_tabs_survey_send_button" tools:ignore="UnusedResources">Send</string>
<string name="inactive_tabs_survey_send_button">Send</string>
<!-- Content description for inactive tabs survey close button -->
<string name="inactive_tabs_survey_close_button_content_description" tools:ignore="UnusedResources">Close</string>
<string name="inactive_tabs_survey_close_button_content_description">Close</string>
<!-- Default browser experiment -->
<string name="default_browser_experiment_card_text">Set links from websites, emails, and messages to open automatically in Firefox.</string>

Loading…
Cancel
Save