mirror of
https://github.com/fork-maintainers/iceraven-browser
synced 2024-11-03 23:15:31 +00:00
[fenix] For https://github.com/mozilla-mobile/fenix/issues/18375: Add experiment for set default browser New Tab card.
This commit is contained in:
parent
a5d8e40932
commit
ed8d36520e
@ -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
|
||||
|
46
app/src/main/res/layout/experiment_default_browser.xml
Normal file
46
app/src/main/res/layout/experiment_default_browser.xml
Normal file
@ -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…
Reference in New Issue
Block a user