1
0
Fork 0

For #12364 - Only show PWA prompt the third time a user visits installable site

master
ekager 2020-07-16 14:44:24 -04:00 committed by Emily Kager
parent ac3df6bc5e
commit e358f95eed
9 changed files with 107 additions and 44 deletions

View File

@ -40,7 +40,7 @@ import org.mozilla.fenix.ext.navigateSafe
import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.ext.resetPoliciesAfter
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.shortcut.FirstTimePwaObserver
import org.mozilla.fenix.shortcut.PwaOnboardingObserver
import org.mozilla.fenix.trackingprotection.TrackingProtectionOverlay
/**
@ -156,9 +156,9 @@ class BrowserFragment : BaseBrowserFragment(), UserInteractionHandler {
}
session?.register(toolbarSessionObserver, viewLifecycleOwner, autoPause = true)
if (settings.shouldShowFirstTimePwaFragment) {
if (!settings.userKnowsAboutPwas) {
session?.register(
FirstTimePwaObserver(
PwaOnboardingObserver(
navController = findNavController(),
settings = settings,
webAppUseCases = context.components.useCases.webAppUseCases

View File

@ -74,6 +74,6 @@ object Performance {
* Disables the first time PWA popup.
*/
private fun disableFirstTimePWAPopup(context: Context) {
Settings.getInstance(context).userKnowsAboutPWAs = true
Settings.getInstance(context).userKnowsAboutPwas = true
}
}

View File

@ -16,9 +16,9 @@ import org.mozilla.fenix.R
import org.mozilla.fenix.ext.requireComponents
/**
* Dialog displayed the first time the user navigates to an installable web app.
* Dialog displayed the third time the user navigates to an installable web app.
*/
class FirstTimePwaFragment : DialogFragment() {
class PwaOnboardingDialogFragment : DialogFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(STYLE_NO_TITLE, R.style.CreateShortcutDialogStyle)
@ -28,7 +28,7 @@ class FirstTimePwaFragment : DialogFragment() {
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? = inflater.inflate(R.layout.fragment_pwa_first_time, container, false)
): View? = inflater.inflate(R.layout.fragment_pwa_onboarding, container, false)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

View File

@ -14,20 +14,23 @@ import org.mozilla.fenix.ext.nav
import org.mozilla.fenix.utils.Settings
/**
* Displays the [FirstTimePwaFragment] info dialog when a PWA is first opened in the browser.
* Displays the [PwaOnboardingDialogFragment] info dialog when a PWA is opened in the browser for the third time.
*/
class FirstTimePwaObserver(
class PwaOnboardingObserver(
private val navController: NavController,
private val settings: Settings,
private val webAppUseCases: WebAppUseCases
) : Session.Observer {
override fun onWebAppManifestChanged(session: Session, manifest: WebAppManifest?) {
if (webAppUseCases.isInstallable() && settings.shouldShowFirstTimePwaFragment) {
val directions = BrowserFragmentDirections.actionBrowserFragmentToFirstTimePwaFragment()
navController.nav(R.id.browserFragment, directions)
settings.userKnowsAboutPWAs = true
if (webAppUseCases.isInstallable() && !settings.userKnowsAboutPwas) {
settings.incrementVisitedInstallableCount()
if (settings.shouldShowPwaOnboarding) {
val directions =
BrowserFragmentDirections.actionBrowserFragmentToPwaOnboardingDialogFragment()
navController.nav(R.id.browserFragment, directions)
settings.userKnowsAboutPwas = true
}
}
}
}

View File

@ -53,6 +53,7 @@ class Settings private constructor(
const val showLoginsSecureWarningSyncMaxCount = 1
const val showLoginsSecureWarningMaxCount = 1
const val trackingProtectionOnboardingMaximumCount = 1
const val pwaVisitsToShowPromptMaxCount = 3
const val FENIX_PREFERENCES = "fenix_preferences"
private const val showSearchWidgetCFRMaxCount = 3
@ -146,9 +147,18 @@ class Settings private constructor(
// If any of the prefs have been modified, quit displaying the fenix moved tip
fun shouldDisplayFenixMovingTip(): Boolean =
preferences.getBoolean(appContext.getString(R.string.pref_key_migrating_from_fenix_nightly_tip), true) &&
preferences.getBoolean(appContext.getString(R.string.pref_key_migrating_from_firefox_nightly_tip), true) &&
preferences.getBoolean(appContext.getString(R.string.pref_key_migrating_from_fenix_tip), true)
preferences.getBoolean(
appContext.getString(R.string.pref_key_migrating_from_fenix_nightly_tip),
true
) &&
preferences.getBoolean(
appContext.getString(R.string.pref_key_migrating_from_firefox_nightly_tip),
true
) &&
preferences.getBoolean(
appContext.getString(R.string.pref_key_migrating_from_fenix_tip),
true
)
private val activeSearchCount by intPreference(
appContext.getPreferenceKey(R.string.pref_key_search_count),
@ -167,9 +177,9 @@ class Settings private constructor(
fun shouldDisplaySearchWidgetCFR(): Boolean =
isActiveSearcher &&
searchWidgetCFRDismissCount < showSearchWidgetCFRMaxCount &&
!searchWidgetInstalled &&
!searchWidgetCFRManuallyDismissed
searchWidgetCFRDismissCount < showSearchWidgetCFRMaxCount &&
!searchWidgetInstalled &&
!searchWidgetCFRManuallyDismissed
private val searchWidgetCFRDisplayCount by intPreference(
appContext.getPreferenceKey(R.string.pref_key_search_widget_cfr_display_count),
@ -236,10 +246,10 @@ class Settings private constructor(
val isCrashReportingEnabled: Boolean
get() = isCrashReportEnabledInBuild &&
preferences.getBoolean(
appContext.getPreferenceKey(R.string.pref_key_crash_reporter),
true
)
preferences.getBoolean(
appContext.getPreferenceKey(R.string.pref_key_crash_reporter),
true
)
val isRemoteDebuggingEnabled by booleanPreference(
appContext.getPreferenceKey(R.string.pref_key_remote_debugging),
@ -267,7 +277,7 @@ class Settings private constructor(
val shouldShowTrackingProtectionOnboarding: Boolean
get() = !isOverrideTPPopupsForPerformanceTest &&
(trackingProtectionOnboardingCount < trackingProtectionOnboardingMaximumCount &&
!trackingProtectionOnboardingShownThisSession)
!trackingProtectionOnboardingShownThisSession)
var showSecretDebugMenuThisSession = false
@ -418,14 +428,14 @@ class Settings private constructor(
BrowsingMode.Normal
}
}
set(value) {
val lastKnownModeWasPrivate = (value == BrowsingMode.Private)
preferences.edit()
.putBoolean(
appContext.getPreferenceKey(R.string.pref_key_last_known_mode_private),
lastKnownModeWasPrivate)
appContext.getPreferenceKey(R.string.pref_key_last_known_mode_private),
lastKnownModeWasPrivate
)
.apply()
field = value
@ -495,7 +505,9 @@ class Settings private constructor(
}
val accessibilityServicesEnabled: Boolean
get() { return touchExplorationIsEnabled || switchServiceIsEnabled }
get() {
return touchExplorationIsEnabled || switchServiceIsEnabled
}
val toolbarSettingString: String
get() = when {
@ -569,22 +581,41 @@ class Settings private constructor(
default = false
)
val shouldShowFirstTimePwaFragment: Boolean
fun incrementVisitedInstallableCount() {
preferences.edit().putInt(
appContext.getPreferenceKey(R.string.pref_key_install_pwa_visits),
pwaInstallableVisitCount + 1
).apply()
}
@VisibleForTesting(otherwise = PRIVATE)
internal val pwaInstallableVisitCount by intPreference(
appContext.getPreferenceKey(R.string.pref_key_install_pwa_visits),
default = 0
)
private val userNeedsToVisitInstallableSites: Boolean
get() = pwaInstallableVisitCount < pwaVisitsToShowPromptMaxCount
val shouldShowPwaOnboarding: Boolean
get() {
// We only want to show this on the 3rd time a user visits a site
if (userNeedsToVisitInstallableSites) return false
// ShortcutManager::pinnedShortcuts is only available on Oreo+
if (!userKnowsAboutPWAs && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val alreadyHavePWaInstalled =
if (!userKnowsAboutPwas && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val alreadyHavePwaInstalled =
appContext.getSystemService(ShortcutManager::class.java)
.pinnedShortcuts.size > 0
// Users know about PWAs onboarding if they already have PWAs installed.
userKnowsAboutPWAs = alreadyHavePWaInstalled
userKnowsAboutPwas = alreadyHavePwaInstalled
}
// Show dialog only if user does not know abut PWAs
return !userKnowsAboutPWAs
return !userKnowsAboutPwas
}
var userKnowsAboutPWAs by booleanPreference(
var userKnowsAboutPwas by booleanPreference(
appContext.getPreferenceKey(R.string.pref_key_user_knows_about_pwa),
default = false
)
@ -809,8 +840,12 @@ class Settings private constructor(
var savedLoginsSortingStrategy: SortingStrategy
get() {
return when (savedLoginsSortingStrategyString) {
SavedLoginsFragment.SORTING_STRATEGY_ALPHABETICALLY -> SortingStrategy.Alphabetically(appContext)
SavedLoginsFragment.SORTING_STRATEGY_LAST_USED -> SortingStrategy.LastUsed(appContext)
SavedLoginsFragment.SORTING_STRATEGY_ALPHABETICALLY -> SortingStrategy.Alphabetically(
appContext
)
SavedLoginsFragment.SORTING_STRATEGY_LAST_USED -> SortingStrategy.LastUsed(
appContext
)
else -> SortingStrategy.Alphabetically(appContext)
}
}

View File

@ -10,7 +10,7 @@
android:layout_height="match_parent"
android:background="@drawable/scrim_background"
android:fitsSystemWindows="true"
tools:context="org.mozilla.fenix.shortcut.FirstTimePwaFragment">
tools:context="org.mozilla.fenix.shortcut.PwaOnboardingDialogFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@ -221,8 +221,8 @@
android:id="@+id/action_browserFragment_to_createShortcutFragment"
app:destination="@id/createShortcutFragment" />
<action
android:id="@+id/action_browserFragment_to_firstTimePwaFragment"
app:destination="@id/firstTimePwaFragment" />
android:id="@+id/action_browserFragment_to_pwaOnboardingDialogFragment"
app:destination="@id/pwaOnboardingDialogFragment" />
<action
android:id="@+id/action_browserFragment_to_quickSettingsSheetDialogFragment"
app:destination="@id/quickSettingsSheetDialogFragment" />
@ -680,10 +680,9 @@
android:name="org.mozilla.fenix.shortcut.CreateShortcutFragment"
tools:layout="@layout/fragment_create_shortcut" />
<dialog
android:id="@+id/firstTimePwaFragment"
android:name="org.mozilla.fenix.shortcut.FirstTimePwaFragment"
android:label="fragment_pwa_first_time"
tools:layout="@layout/fragment_pwa_first_time" />
android:id="@+id/pwaOnboardingDialogFragment"
android:name="org.mozilla.fenix.shortcut.PwaOnboardingDialogFragment"
tools:layout="@layout/fragment_pwa_onboarding" />
<dialog
android:id="@+id/shareFragment"

View File

@ -56,6 +56,7 @@
<string name="pref_key_private_mode_opened" translatable="false">pref_key_private_mode_opened</string>
<string name="pref_key_open_in_app_opened" translatable="false">pref_key_open_in_app_opened</string>
<string name="pref_key_install_pwa_opened" translatable="false">pref_key_install_pwa_opened</string>
<string name="pref_key_install_pwa_visits" translatable="false">pref_key_install_pwa_visits</string>
<!-- Data Choices -->
<string name="pref_key_telemetry" translatable="false">pref_key_telemetry</string>

View File

@ -351,6 +351,31 @@ class SettingsTest {
assertTrue(settings.shouldShowSearchSuggestions)
}
@Test
fun showPwaFragment() {
// When just created
// Then
assertFalse(settings.shouldShowPwaOnboarding)
// When visited once
settings.incrementVisitedInstallableCount()
// Then
assertFalse(settings.shouldShowPwaOnboarding)
// When visited twice
settings.incrementVisitedInstallableCount()
// Then
assertFalse(settings.shouldShowPwaOnboarding)
// When visited thrice
settings.incrementVisitedInstallableCount()
// Then
assertTrue(settings.shouldShowPwaOnboarding)
}
@Test
fun sitePermissionsPhoneFeatureCameraAction() {
// When just created