For #18375: Add experiment for set default browser New Tab card.

upstream-sync
mcarare 3 years ago committed by Mihai Adrian Carare
parent cbfba4478b
commit ba218e638b

@ -20,5 +20,6 @@ class ExperimentBranch {
const val A1 = "a1"
const val A2 = "a2"
const val DEFAULT_BROWSER_TOOLBAR_MENU = "default_browser_toolbar_menu"
const val DEFAULT_BROWSER_NEW_TAB_BANNER = "default_browser_newtab_banner"
}
}

@ -225,7 +225,8 @@ class HomeFragment : Fragment() {
)
).getTip()
},
showCollectionPlaceholder = components.settings.showCollectionsPlaceholderOnHome
showCollectionPlaceholder = components.settings.showCollectionsPlaceholderOnHome,
showSetAsDefaultBrowserCard = components.settings.shouldShowSetAsDefaultBrowserCard()
)
)
}

@ -48,7 +48,8 @@ data class HomeFragmentState(
val mode: Mode,
val topSites: List<TopSite>,
val tip: Tip? = null,
val showCollectionPlaceholder: Boolean
val showCollectionPlaceholder: Boolean,
val showSetAsDefaultBrowserCard: Boolean
) : State
sealed class HomeFragmentAction : Action {
@ -69,6 +70,7 @@ sealed class HomeFragmentAction : Action {
data class TopSitesChange(val topSites: List<TopSite>) : HomeFragmentAction()
data class RemoveTip(val tip: Tip) : HomeFragmentAction()
object RemoveCollectionsPlaceholder : HomeFragmentAction()
object RemoveSetDefaultBrowserCard : HomeFragmentAction()
}
private fun homeFragmentStateReducer(
@ -102,5 +104,6 @@ private fun homeFragmentStateReducer(
is HomeFragmentAction.RemoveCollectionsPlaceholder -> {
state.copy(showCollectionPlaceholder = false)
}
is HomeFragmentAction.RemoveSetDefaultBrowserCard -> state.copy(showSetAsDefaultBrowserCard = false)
}
}

@ -24,6 +24,7 @@ import org.mozilla.fenix.home.sessioncontrol.viewholders.NoCollectionsMessageVie
import org.mozilla.fenix.home.sessioncontrol.viewholders.PrivateBrowsingDescriptionViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.TabInCollectionViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.TopSitePagerViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.ExperimentDefaultBrowserCardViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingAutomaticSignInViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingFinishViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingHeaderViewHolder
@ -116,6 +117,8 @@ sealed class AdapterItem(@LayoutRes val viewType: Int) {
val state: OnboardingState.SignedOutCanAutoSignIn
) : AdapterItem(OnboardingAutomaticSignInViewHolder.LAYOUT_ID)
object ExperimentDefaultBrowserCard : AdapterItem(ExperimentDefaultBrowserCardViewHolder.LAYOUT_ID)
object OnboardingThemePicker : AdapterItem(OnboardingThemePickerViewHolder.LAYOUT_ID)
object OnboardingTrackingProtection :
AdapterItem(OnboardingTrackingProtectionViewHolder.LAYOUT_ID)
@ -207,6 +210,8 @@ class SessionControlAdapter(
OnboardingToolbarPositionPickerViewHolder.LAYOUT_ID -> OnboardingToolbarPositionPickerViewHolder(
view
)
ExperimentDefaultBrowserCardViewHolder.LAYOUT_ID -> ExperimentDefaultBrowserCardViewHolder(view, interactor)
else -> throw IllegalStateException()
}
}

@ -39,7 +39,7 @@ import org.mozilla.fenix.components.tips.Tip
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.metrics
import org.mozilla.fenix.ext.nav
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.ext.openSetDefaultBrowserOption
import org.mozilla.fenix.home.HomeFragment
import org.mozilla.fenix.home.HomeFragmentAction
import org.mozilla.fenix.home.HomeFragmentDirections
@ -168,6 +168,16 @@ interface SessionControlController {
* @see [CollectionInteractor.onCollectionMenuOpened] and [TopSiteInteractor.onTopSiteMenuOpened]
*/
fun handleMenuOpened()
/**
* @see [ExperimentCardInteractor.onSetDefaultBrowserClicked]
*/
fun handleSetDefaultBrowser()
/**
* @see [ExperimentCardInteractor.onCloseExperimentCardClicked]
*/
fun handleCloseExperimentCard()
}
@Suppress("TooManyFunctions", "LargeClass")
@ -554,4 +564,14 @@ class DefaultSessionControlController(
)
navController.nav(R.id.homeFragment, directions)
}
override fun handleSetDefaultBrowser() {
settings.userDismissedExperimentCard = true
activity.openSetDefaultBrowserOption()
}
override fun handleCloseExperimentCard() {
settings.userDismissedExperimentCard = true
fragmentStore.dispatch(HomeFragmentAction.RemoveSetDefaultBrowserCard)
}
}

@ -190,6 +190,18 @@ interface TopSiteInteractor {
fun onTopSiteMenuOpened()
}
interface ExperimentCardInteractor {
/**
* Called when set default browser button is clicked
*/
fun onSetDefaultBrowserClicked()
/**
* Called when close button on experiment card
*/
fun onCloseExperimentCardClicked()
}
/**
* Interactor for the Home screen.
* Provides implementations for the CollectionInteractor, OnboardingInteractor,
@ -199,7 +211,7 @@ interface TopSiteInteractor {
class SessionControlInteractor(
private val controller: SessionControlController
) : CollectionInteractor, OnboardingInteractor, TopSiteInteractor, TipInteractor,
TabSessionInteractor, ToolbarInteractor {
TabSessionInteractor, ToolbarInteractor, ExperimentCardInteractor {
override fun onCollectionAddTabTapped(collection: TabCollection) {
controller.handleCollectionAddTabTapped(collection)
}
@ -295,4 +307,12 @@ class SessionControlInteractor(
override fun onTopSiteMenuOpened() {
controller.handleMenuOpened()
}
override fun onSetDefaultBrowserClicked() {
controller.handleSetDefaultBrowser()
}
override fun onCloseExperimentCardClicked() {
controller.handleCloseExperimentCard()
}
}

@ -21,18 +21,23 @@ import org.mozilla.fenix.home.OnboardingState
// This method got a little complex with the addition of the tab tray feature flag
// When we remove the tabs from the home screen this will get much simpler again.
@Suppress("ComplexMethod")
@Suppress("ComplexMethod", "LongParameterList")
private fun normalModeAdapterItems(
topSites: List<TopSite>,
collections: List<TabCollection>,
expandedCollections: Set<Long>,
tip: Tip?,
showCollectionsPlaceholder: Boolean
showCollectionsPlaceholder: Boolean,
showSetAsDefaultBrowserCard: Boolean
): List<AdapterItem> {
val items = mutableListOf<AdapterItem>()
tip?.let { items.add(AdapterItem.TipItem(it)) }
if (showSetAsDefaultBrowserCard) {
items.add(AdapterItem.ExperimentDefaultBrowserCard)
}
if (topSites.isNotEmpty()) {
items.add(AdapterItem.TopSitePager(topSites))
}
@ -110,7 +115,8 @@ private fun HomeFragmentState.toAdapterList(): List<AdapterItem> = when (mode) {
collections,
expandedCollections,
tip,
showCollectionPlaceholder
showCollectionPlaceholder,
showSetAsDefaultBrowserCard
)
is Mode.Private -> privateModeAdapterItems()
is Mode.Onboarding -> onboardingAdapterItems(mode.state)

@ -0,0 +1,36 @@
/* 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.home.sessioncontrol.viewholders.onboarding
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.experiment_default_browser.view.*
import org.mozilla.fenix.R
import org.mozilla.fenix.ext.increaseTapArea
import org.mozilla.fenix.home.sessioncontrol.SessionControlInteractor
class ExperimentDefaultBrowserCardViewHolder(
view: View,
private val interactor: SessionControlInteractor
) : RecyclerView.ViewHolder(view) {
init {
view.set_default_browser.setOnClickListener {
interactor.onSetDefaultBrowserClicked()
}
view.close.apply {
increaseTapArea(CLOSE_BUTTON_EXTRA_DPS)
setOnClickListener {
interactor.onCloseExperimentCardClicked()
}
}
}
companion object {
internal const val LAYOUT_ID = R.layout.experiment_default_browser
private const val CLOSE_BUTTON_EXTRA_DPS = 38
}
}

@ -33,8 +33,11 @@ import org.mozilla.fenix.components.metrics.MozillaProductDetector
import org.mozilla.fenix.components.settings.counterPreference
import org.mozilla.fenix.components.settings.featureFlagPreference
import org.mozilla.fenix.components.toolbar.ToolbarPosition
import org.mozilla.fenix.experiments.ExperimentBranch
import org.mozilla.fenix.experiments.Experiments
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.getPreferenceKey
import org.mozilla.fenix.ext.withExperiment
import org.mozilla.fenix.settings.PhoneFeature
import org.mozilla.fenix.settings.deletebrowsingdata.DeleteBrowsingDataOnQuitType
import org.mozilla.fenix.settings.logins.SavedLoginsSortingStrategyMenu
@ -61,6 +64,7 @@ class Settings(private val appContext: Context) : PreferencesHolder {
private const val ALLOWED_INT = 2
private const val CFR_COUNT_CONDITION_FOCUS_INSTALLED = 1
private const val CFR_COUNT_CONDITION_FOCUS_NOT_INSTALLED = 3
private const val APP_LAUNCHES_TO_SHOW_DEFAULT_BROWSER_CARD = 3
const val ONE_DAY_MS = 60 * 60 * 24 * 1000L
const val THREE_DAYS_MS = 3 * ONE_DAY_MS
@ -292,6 +296,31 @@ class Settings(private val appContext: Context) : PreferencesHolder {
default = false
)
/**
* Shows if the user has chosen to close the set default browser experiment card
* on home screen or has clicked the set as default browser button.
*/
var userDismissedExperimentCard by booleanPreference(
appContext.getPreferenceKey(R.string.pref_key_experiment_card_home),
default = false
)
/**
* Shows if the set default browser experiment card should be shown on home screen.
*/
fun shouldShowSetAsDefaultBrowserCard(): Boolean {
val browsers = BrowsersCache.all(appContext)
val experiments = appContext.components.analytics.experiments
val isExperimentBranch =
experiments.withExperiment(Experiments.DEFAULT_BROWSER) { experimentBranch ->
(experimentBranch == ExperimentBranch.DEFAULT_BROWSER_NEW_TAB_BANNER)
}
return isExperimentBranch &&
!userDismissedExperimentCard &&
!browsers.isFirefoxDefaultBrowser &&
numberOfAppLaunches > APP_LAUNCHES_TO_SHOW_DEFAULT_BROWSER_CARD
}
var listTabView by booleanPreference(
appContext.getPreferenceKey(R.string.pref_key_tab_view_list),
default = true

@ -0,0 +1,46 @@
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/experiment_card"
style="@style/OnboardingCardLightWithPadding"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageButton
android:id="@+id/close"
android:layout_width="10dp"
android:layout_height="10dp"
android:background="?selectableItemBackgroundBorderless"
android:contentDescription="@string/content_description_close_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/description_text"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_close"
tools:srcCompat="@drawable/ic_close" />
<TextView
android:id="@+id/description_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="@string/default_browser_experiment_card_text"
android:textAppearance="@style/Body14TextStyle"
app:layout_constraintBottom_toTopOf="@id/set_default_browser"
app:layout_constraintEnd_toStartOf="@id/close"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/set_default_browser"
style="@style/PositiveButton"
android:layout_height="36dp"
android:background="@drawable/rounded_button_background"
android:text="@string/preferences_set_as_default_browser"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/description_text" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -263,6 +263,9 @@
<string name="pref_key_open_next_tab_desktop_mode" translatable="false">pref_key_open_next_tab_desktop_mode</string>
<!-- Set default browser experiment card-->
<string name="pref_key_experiment_card_home" translatable="false">pref_key_experiment_card_home</string>
<!-- Secret Info Setting Keys -->
<string name="pref_key_secret_debug_info" translatable="false">pref_key_secret_debug_info</string>
<string name="pref_key_leanplum_user_id" translatable="false">pref_key_leanplum_user_id</string>

@ -1702,6 +1702,9 @@
<!-- Dialog button text for canceling the rename top site prompt. -->
<string name="top_sites_rename_dialog_cancel">Cancel</string>
<!-- Default browser experiment -->
<string name="default_browser_experiment_card_text">Set links from websites, emails, and messages to open automatically in Firefox.</string>
<!-- Content description for close button in collection placeholder. -->
<string name="remove_home_collection_placeholder_content_description">Remove</string>

@ -128,7 +128,8 @@ class DefaultSessionControlControllerTest {
expandedCollections = emptySet(),
mode = Mode.Normal,
topSites = emptyList(),
showCollectionPlaceholder = true
showCollectionPlaceholder = true,
showSetAsDefaultBrowserCard = true
)
every { navController.currentDestination } returns mockk {

@ -55,7 +55,8 @@ class HomeFragmentStoreTest {
expandedCollections = emptySet(),
mode = currentMode.getCurrentMode(),
topSites = emptyList(),
showCollectionPlaceholder = true
showCollectionPlaceholder = true,
showSetAsDefaultBrowserCard = true
)
homeFragmentStore = HomeFragmentStore(homeFragmentState)

Loading…
Cancel
Save