For #19789 Start on Home after some amount of time
This commit is contained in:
parent
f9428759db
commit
f0bb70e354
|
@ -6,6 +6,7 @@ package org.mozilla.fenix
|
|||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.Intent.ACTION_MAIN
|
||||
import android.content.res.Configuration
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
|
@ -116,6 +117,7 @@ import org.mozilla.fenix.tabstray.TabsTrayFragmentDirections
|
|||
import org.mozilla.fenix.theme.DefaultThemeManager
|
||||
import org.mozilla.fenix.theme.ThemeManager
|
||||
import org.mozilla.fenix.utils.BrowsersCache
|
||||
import org.mozilla.fenix.utils.Settings
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
/**
|
||||
|
@ -217,8 +219,9 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
|
|||
it.start()
|
||||
}
|
||||
|
||||
if (isActivityColdStarted(intent, savedInstanceState) &&
|
||||
!externalSourceIntentProcessors.any { it.process(intent, navHost.navController, this.intent) }) {
|
||||
if (!shouldStartOnHome() &&
|
||||
shouldNavigateBrowserFragmentOnCouldStart(savedInstanceState)
|
||||
) {
|
||||
navigateToBrowserOnColdStart()
|
||||
}
|
||||
|
||||
|
@ -980,6 +983,32 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
|
|||
startingIntent.flags and Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY == 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the user should be redirected to the [BrowserFragment] or to the [HomeFragment],
|
||||
* links from an external apps should always opened in the [BrowserFragment].
|
||||
*/
|
||||
fun shouldStartOnHome(intent: Intent? = this.intent): Boolean {
|
||||
return components.strictMode.resetAfter(StrictMode.allowThreadDiskReads()) {
|
||||
// We only want to open on home when users tap the app,
|
||||
// we want to ignore other cases when the app gets open by users clicking on links.
|
||||
getSettings().shouldStartOnHome() && intent?.action == ACTION_MAIN
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
internal fun getSettings(): Settings = settings()
|
||||
|
||||
private fun shouldNavigateBrowserFragmentOnCouldStart(savedInstanceState: Bundle?): Boolean {
|
||||
return isActivityColdStarted(intent, savedInstanceState) &&
|
||||
!externalSourceIntentProcessors.any {
|
||||
it.process(
|
||||
intent,
|
||||
navHost.navController,
|
||||
this.intent
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val OPEN_TO_BROWSER = "open_to_browser"
|
||||
const val OPEN_TO_BROWSER_AND_LOAD = "open_to_browser_and_load"
|
||||
|
|
|
@ -8,6 +8,7 @@ import android.content.Context
|
|||
import android.os.StrictMode
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.navigation.fragment.findNavController
|
||||
|
@ -183,7 +184,7 @@ class BrowserFragment : BaseBrowserFragment(), UserInteractionHandler {
|
|||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
|
||||
updateLastBrowseActivity()
|
||||
pwaOnboardingObserver?.stop()
|
||||
}
|
||||
|
||||
|
@ -292,4 +293,14 @@ class BrowserFragment : BaseBrowserFragment(), UserInteractionHandler {
|
|||
) + ContextMenuCandidate.createOpenInExternalAppCandidate(requireContext(),
|
||||
contextMenuCandidateAppLinksUseCases)
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the last time the user was active on the [BrowserFragment].
|
||||
* This is useful to determine if the user has to start on the [HomeFragment]
|
||||
* or it should go directly to the [BrowserFragment].
|
||||
*/
|
||||
@VisibleForTesting
|
||||
internal fun updateLastBrowseActivity() {
|
||||
requireContext().settings().lastBrowseActivity = System.currentTimeMillis()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,9 @@ class TabsSettingsFragment : PreferenceFragmentCompat() {
|
|||
private lateinit var radioOneDay: RadioButtonPreference
|
||||
private lateinit var radioOneWeek: RadioButtonPreference
|
||||
private lateinit var radioOneMonth: RadioButtonPreference
|
||||
private lateinit var startOnHomeRadioFourHours: RadioButtonPreference
|
||||
private lateinit var startOnHomeRadioAlways: RadioButtonPreference
|
||||
private lateinit var startOnHomeRadioNever: RadioButtonPreference
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.tabs_preferences, rootKey)
|
||||
|
@ -53,6 +56,10 @@ class TabsSettingsFragment : PreferenceFragmentCompat() {
|
|||
radioOneWeek = requirePreference(R.string.pref_key_close_tabs_after_one_week)
|
||||
radioOneMonth = requirePreference(R.string.pref_key_close_tabs_after_one_month)
|
||||
|
||||
startOnHomeRadioFourHours = requirePreference(R.string.pref_key_start_on_home_after_four_hours)
|
||||
startOnHomeRadioAlways = requirePreference(R.string.pref_key_start_on_home_always)
|
||||
startOnHomeRadioNever = requirePreference(R.string.pref_key_start_on_home_never)
|
||||
|
||||
setupRadioGroups()
|
||||
}
|
||||
|
||||
|
@ -68,5 +75,11 @@ class TabsSettingsFragment : PreferenceFragmentCompat() {
|
|||
radioOneMonth,
|
||||
radioOneWeek
|
||||
)
|
||||
|
||||
addToRadioGroup(
|
||||
startOnHomeRadioFourHours,
|
||||
startOnHomeRadioAlways,
|
||||
startOnHomeRadioNever
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,6 +66,7 @@ class Settings(private val appContext: Context) : PreferencesHolder {
|
|||
private const val CFR_COUNT_CONDITION_FOCUS_NOT_INSTALLED = 3
|
||||
private const val APP_LAUNCHES_TO_SHOW_DEFAULT_BROWSER_CARD = 3
|
||||
|
||||
const val FOUR_HOURS_MS = 60 * 60 * 4 * 1000L
|
||||
const val ONE_DAY_MS = 60 * 60 * 24 * 1000L
|
||||
const val THREE_DAYS_MS = 3 * ONE_DAY_MS
|
||||
const val ONE_WEEK_MS = 60 * 60 * 24 * 7 * 1000L
|
||||
|
@ -351,6 +352,56 @@ class Settings(private val appContext: Context) : PreferencesHolder {
|
|||
default = false
|
||||
)
|
||||
|
||||
/**
|
||||
* Indicates the last time when the user was interacting with the [BrowserFragment],
|
||||
* This is useful to determine if the user has to start on the [HomeFragment]
|
||||
* or it should go directly to the [BrowserFragment].
|
||||
*/
|
||||
var lastBrowseActivity by longPreference(
|
||||
appContext.getPreferenceKey(R.string.pref_key_last_browse_activity_time),
|
||||
default = timeNowInMillis()
|
||||
)
|
||||
|
||||
/**
|
||||
* Indicates if the user has selected the option to start on the home screen after
|
||||
* four hours of inactivity.
|
||||
*/
|
||||
var startOnHomeAfterFourHours by booleanPreference(
|
||||
appContext.getPreferenceKey(R.string.pref_key_start_on_home_after_four_hours),
|
||||
default = true
|
||||
)
|
||||
|
||||
/**
|
||||
* Indicates if the user has selected the option to always start on the home screen.
|
||||
*/
|
||||
var startOnHomeAlways by booleanPreference(
|
||||
appContext.getPreferenceKey(R.string.pref_key_start_on_home_always),
|
||||
default = false
|
||||
)
|
||||
|
||||
/**
|
||||
* Indicates if the user has selected the option to never start on the home screen.
|
||||
*/
|
||||
var startOnHomeNever by booleanPreference(
|
||||
appContext.getPreferenceKey(R.string.pref_key_start_on_home_never),
|
||||
default = false
|
||||
)
|
||||
|
||||
/**
|
||||
* Indicates if the user should start on the home screen, based on the user's preferences.
|
||||
*/
|
||||
fun shouldStartOnHome(): Boolean {
|
||||
return when {
|
||||
startOnHomeAfterFourHours -> timeNowInMillis() - lastBrowseActivity >= FOUR_HOURS_MS
|
||||
startOnHomeAlways -> true
|
||||
startOnHomeNever -> false
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
internal fun timeNowInMillis(): Long = System.currentTimeMillis()
|
||||
|
||||
fun getTabTimeout(): Long = when {
|
||||
closeTabsAfterOneDay -> ONE_DAY_MS
|
||||
closeTabsAfterOneWeek -> ONE_WEEK_MS
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
<string name="pref_key_install_pwa_visits" translatable="false">pref_key_install_pwa_visits</string>
|
||||
<string name="pref_key_times_app_opened" translatable="false">pref_key_times_app_opened</string>
|
||||
<string name="pref_key_last_review_prompt_shown_time" translatable="false">pref_key_last_review_prompt_shown_time</string>
|
||||
<string name="pref_key_last_browse_activity_time" translatable="false">pref_key_last_browse_activity_time</string>
|
||||
<string name="pref_key_last_cfr_shown_time" translatable="false">pref_key_last_cfr_shown_time</string>
|
||||
|
||||
<!-- Data Choices -->
|
||||
|
@ -263,7 +264,9 @@
|
|||
<string name="pref_key_close_tabs_after_one_week" translatable="false">pref_key_close_tabs_after_one_week</string>
|
||||
<string name="pref_key_close_tabs_after_one_month" translatable="false">pref_key_close_tabs_after_one_month</string>
|
||||
<string name="pref_key_allow_third_party_root_certs" translatable="false">pref_key_allow_third_party_cert_roots</string>
|
||||
|
||||
<string name="pref_key_start_on_home_after_four_hours" translatable="false">pref_key_start_on_home_after_four_hours</string>
|
||||
<string name="pref_key_start_on_home_always" translatable="false">pref_key_start_on_home_always</string>
|
||||
<string name="pref_key_start_on_home_never" translatable="false">pref_key_start_on_home_never</string>
|
||||
<string name="pref_key_camera_permissions_needed" translatable="false">pref_key_camera_permissions_needed</string>
|
||||
|
||||
<string name="pref_key_return_to_browser" translatable="false">pref_key_return_to_browser</string>
|
||||
|
|
|
@ -570,6 +570,15 @@
|
|||
<!-- Option for auto closing tabs that will auto close tabs after one month -->
|
||||
<string name="close_tabs_after_one_month">After one month</string>
|
||||
|
||||
<!-- Start on Home -->
|
||||
<!-- Title of a preference that allows a user to indicate after a specified amount of time when the app should start on the home screen -->
|
||||
<string name="preferences_start_on_home">Start on home</string>
|
||||
<!-- Option for staring on the home screen after after four hours or inactivity -->
|
||||
<string name="start_on_home_after_four_hours">After four hours</string>
|
||||
<!-- Option for always staring on the home screen -->
|
||||
<string name="start_on_home_always">Always</string>
|
||||
<!-- Option for never staring on the home screen -->
|
||||
<string name="start_on_home_never">Never</string>
|
||||
<!-- Summary for tabs preference when auto closing tabs setting is set to manual close-->
|
||||
<string name="close_tabs_manually_summary">Close manually</string>
|
||||
<!-- Summary for tabs preference when auto closing tabs setting is set to auto close tabs after one day-->
|
||||
|
|
|
@ -45,4 +45,26 @@
|
|||
android:key="@string/pref_key_close_tabs_after_one_month"
|
||||
android:title="@string/close_tabs_after_one_month" />
|
||||
</androidx.preference.PreferenceCategory>
|
||||
|
||||
<androidx.preference.PreferenceCategory
|
||||
android:layout="@layout/preference_cat_style"
|
||||
android:title="@string/preferences_start_on_home"
|
||||
app:allowDividerAbove="true"
|
||||
app:iconSpaceReserved="false">
|
||||
|
||||
<org.mozilla.fenix.settings.RadioButtonPreference
|
||||
android:defaultValue="true"
|
||||
android:key="@string/pref_key_start_on_home_after_four_hours"
|
||||
android:title="@string/start_on_home_after_four_hours" />
|
||||
|
||||
<org.mozilla.fenix.settings.RadioButtonPreference
|
||||
android:defaultValue="false"
|
||||
android:key="@string/pref_key_start_on_home_always"
|
||||
android:title="@string/start_on_home_always" />
|
||||
|
||||
<org.mozilla.fenix.settings.RadioButtonPreference
|
||||
android:defaultValue="false"
|
||||
android:key="@string/pref_key_start_on_home_never"
|
||||
android:title="@string/start_on_home_never" />
|
||||
</androidx.preference.PreferenceCategory>
|
||||
</androidx.preference.PreferenceScreen>
|
||||
|
|
|
@ -139,6 +139,33 @@ class HomeActivityTest {
|
|||
assertFalse(activity.isActivityColdStarted(startingIntent, Bundle()))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN the user has been away for a long time WHEN the user opens the app THEN do start on home`() {
|
||||
val settings: Settings = mockk()
|
||||
val startingIntent = Intent().apply {
|
||||
action = Intent.ACTION_MAIN
|
||||
}
|
||||
every { activity.applicationContext } returns testContext
|
||||
|
||||
every { settings.shouldStartOnHome() } returns true
|
||||
every { activity.getSettings() } returns settings
|
||||
|
||||
assertTrue(activity.shouldStartOnHome(startingIntent))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN the user has been away for a long time WHEN opening a link THEN do not start on home`() {
|
||||
val settings: Settings = mockk()
|
||||
val startingIntent = Intent().apply {
|
||||
action = Intent.ACTION_VIEW
|
||||
}
|
||||
every { settings.shouldStartOnHome() } returns true
|
||||
every { activity.getSettings() } returns settings
|
||||
every { activity.applicationContext } returns testContext
|
||||
|
||||
assertFalse(activity.shouldStartOnHome(startingIntent))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN onCreate is called THEN the duration is measured`() {
|
||||
assertFalse(PerfStartup.homeActivityOnCreate.testHasValue()) // sanity check.
|
||||
|
|
|
@ -44,6 +44,7 @@ import org.mozilla.fenix.ext.components
|
|||
import org.mozilla.fenix.ext.settings
|
||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||
import org.mozilla.fenix.onboarding.FenixOnboarding
|
||||
import org.mozilla.fenix.utils.Settings
|
||||
import java.lang.Exception
|
||||
|
||||
@ExperimentalCoroutinesApi
|
||||
|
@ -369,4 +370,16 @@ class BrowserFragmentTest {
|
|||
|
||||
override fun getLifecycle(): Lifecycle = lifecycleRegistry
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN updating the last browse activity THEN update the associated preference`() {
|
||||
val settings: Settings = mockk(relaxed = true)
|
||||
|
||||
every { browserFragment.context } returns context
|
||||
every { context.settings() } returns settings
|
||||
|
||||
browserFragment.updateLastBrowseActivity()
|
||||
|
||||
verify(exactly = 1) { settings.lastBrowseActivity = any() }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
package org.mozilla.fenix.utils
|
||||
|
||||
import io.mockk.every
|
||||
import io.mockk.spyk
|
||||
import mozilla.components.feature.sitepermissions.SitePermissionsRules
|
||||
import mozilla.components.feature.sitepermissions.SitePermissionsRules.Action.ALLOWED
|
||||
import mozilla.components.feature.sitepermissions.SitePermissionsRules.Action.ASK_TO_ALLOW
|
||||
|
@ -19,6 +21,7 @@ import org.junit.runner.RunWith
|
|||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||
import org.mozilla.fenix.settings.PhoneFeature
|
||||
import org.mozilla.fenix.settings.deletebrowsingdata.DeleteBrowsingDataOnQuitType
|
||||
import java.util.Calendar
|
||||
|
||||
@RunWith(FenixRobolectricTestRunner::class)
|
||||
class SettingsTest {
|
||||
|
@ -690,4 +693,56 @@ class SettingsTest {
|
|||
// Then
|
||||
assertEquals(2, settings.creditCardsSavedCount)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN startOnHomeAlways is selected WHEN calling shouldStartOnHome THEN return true`() {
|
||||
settings.startOnHomeAlways = true
|
||||
settings.startOnHomeNever = false
|
||||
settings.startOnHomeAfterFourHours = false
|
||||
|
||||
assertTrue(settings.shouldStartOnHome())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN startOnHomeNever is selected WHEN calling shouldStartOnHome THEN return be false`() {
|
||||
settings.startOnHomeNever = true
|
||||
settings.startOnHomeAlways = false
|
||||
settings.startOnHomeAfterFourHours = false
|
||||
|
||||
assertFalse(settings.shouldStartOnHome())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN startOnHomeAfterFourHours is selected after four hours of inactivity WHEN calling shouldStartOnHome THEN return true`() {
|
||||
val localSetting = spyk(settings)
|
||||
val now = Calendar.getInstance()
|
||||
|
||||
localSetting.startOnHomeAfterFourHours = true
|
||||
localSetting.startOnHomeNever = false
|
||||
localSetting.startOnHomeAlways = false
|
||||
|
||||
now.timeInMillis = System.currentTimeMillis()
|
||||
localSetting.lastBrowseActivity = now.timeInMillis
|
||||
now.add(Calendar.HOUR, 4)
|
||||
|
||||
every { localSetting.timeNowInMillis() } returns now.timeInMillis
|
||||
|
||||
assertTrue(localSetting.shouldStartOnHome())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN startOnHomeAfterFourHours is selected and with recent activity WHEN calling shouldStartOnHome THEN return false`() {
|
||||
val localSetting = spyk(settings)
|
||||
val now = System.currentTimeMillis()
|
||||
|
||||
localSetting.startOnHomeAfterFourHours = true
|
||||
localSetting.startOnHomeNever = false
|
||||
localSetting.startOnHomeAlways = false
|
||||
|
||||
localSetting.lastBrowseActivity = now
|
||||
|
||||
every { localSetting.timeNowInMillis() } returns now
|
||||
|
||||
assertFalse(localSetting.shouldStartOnHome())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user