Skip to content

Commit

Permalink
For mozilla-mobile#18375: Add experiment for set default browser New …
Browse files Browse the repository at this point in the history
…Tab card.
  • Loading branch information
mcarare committed Apr 9, 2021
1 parent 660f060 commit fb91b2e
Show file tree
Hide file tree
Showing 14 changed files with 185 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
3 changes: 2 additions & 1 deletion app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,8 @@ class HomeFragment : Fragment() {
)
).getTip()
},
showCollectionPlaceholder = components.settings.showCollectionsPlaceholderOnHome
showCollectionPlaceholder = components.settings.showCollectionsPlaceholderOnHome,
showSetAsDefaultBrowserCard = components.settings.shouldShowSetAsDefaultBrowserCard()
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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(
Expand Down Expand Up @@ -102,5 +104,6 @@ private fun homeFragmentStateReducer(
is HomeFragmentAction.RemoveCollectionsPlaceholder -> {
state.copy(showCollectionPlaceholder = false)
}
is HomeFragmentAction.RemoveSetDefaultBrowserCard -> state.copy(showSetAsDefaultBrowserCard = false)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -207,6 +210,8 @@ class SessionControlAdapter(
OnboardingToolbarPositionPickerViewHolder.LAYOUT_ID -> OnboardingToolbarPositionPickerViewHolder(
view
)
ExperimentDefaultBrowserCardViewHolder.LAYOUT_ID -> ExperimentDefaultBrowserCardViewHolder(view, interactor)

else -> throw IllegalStateException()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -168,6 +168,18 @@ interface SessionControlController {
* @see [CollectionInteractor.onCollectionMenuOpened] and [TopSiteInteractor.onTopSiteMenuOpened]
*/
fun handleMenuOpened()

/**
* @see [ExperimentCardInteractor.onSetDefaultBrowserClicked]
*/
fun handleSetDefaultBrowser() {
}

/**
* @see [ExperimentCardInteractor.onCloseExperimentCardClicked]
*/
fun handleCloseExperimentCard() {
}
}

@Suppress("TooManyFunctions", "LargeClass")
Expand Down Expand Up @@ -554,4 +566,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)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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)
}
Expand Down Expand Up @@ -295,4 +307,12 @@ class SessionControlInteractor(
override fun onTopSiteMenuOpened() {
controller.handleMenuOpened()
}

override fun onSetDefaultBrowserClicked() {
controller.handleSetDefaultBrowser()
}

override fun onCloseExperimentCardClicked() {
controller.handleCloseExperimentCard()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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
}
}
28 changes: 28 additions & 0 deletions app/src/main/java/org/mozilla/fenix/utils/Settings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -292,6 +296,30 @@ 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 experiments = appContext.components.analytics.experiments
val isExperimentBranch =
experiments.withExperiment(Experiments.DEFAULT_BROWSER) { experimentBranch ->
(experimentBranch == ExperimentBranch.DEFAULT_BROWSER_NEW_TAB_BANNER)
}
return isExperimentBranch &&
!userDismissedExperimentCard &&
!isDefaultBrowser() &&
numberOfAppLaunches > APP_LAUNCHES_TO_SHOW_DEFAULT_BROWSER_CARD
}

var listTabView by booleanPreference(
appContext.getPreferenceKey(R.string.pref_key_tab_view_list),
default = true
Expand Down
46 changes: 46 additions & 0 deletions app/src/main/res/layout/experiment_default_browser.xml
Original file line number Diff line number Diff line change
@@ -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>
3 changes: 3 additions & 0 deletions app/src/main/res/values/preference_keys.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1700,6 +1700,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>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ class DefaultSessionControlControllerTest {
expandedCollections = emptySet(),
mode = Mode.Normal,
topSites = emptyList(),
showCollectionPlaceholder = true
showCollectionPlaceholder = true,
showSetAsDefaultBrowserCard = true
)

every { navController.currentDestination } returns mockk {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ class HomeFragmentStoreTest {
expandedCollections = emptySet(),
mode = currentMode.getCurrentMode(),
topSites = emptyList(),
showCollectionPlaceholder = true
showCollectionPlaceholder = true,
showSetAsDefaultBrowserCard = true
)

homeFragmentStore = HomeFragmentStore(homeFragmentState)
Expand Down

0 comments on commit fb91b2e

Please sign in to comment.