tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 5e8844a9dd264a537994ed9a0105f917b03b4f56
parent bd0770a10424c19480d1a453af4d3efd6b04e56d
Author: t-p-white <towhite@mozilla.com>
Date:   Fri, 14 Nov 2025 10:06:10 +0000

Bug 1993949 - Refactor the applicationInstalledTime var in Settings used for testing, to use the PackageManagerCompatHelper r=android-reviewers,gmalekpour

Differential Revision: https://phabricator.services.mozilla.com/D272476

Diffstat:
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/ext/Context.kt | 18------------------
Amobile/android/fenix/app/src/main/java/org/mozilla/fenix/termsofuse/GetApplicationInstalledTime.kt | 28++++++++++++++++++++++++++++
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/utils/Settings.kt | 36+++++++++++++++++++++---------------
Amobile/android/fenix/app/src/test/java/org/mozilla/fenix/termsofuse/GetApplicationInstalledTimeTest.kt | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amobile/android/fenix/app/src/test/java/org/mozilla/fenix/utils/FakePackageManagerCompatHelper.kt | 31+++++++++++++++++++++++++++++++
Mmobile/android/fenix/app/src/test/java/org/mozilla/fenix/utils/SettingsTest.kt | 19+++++++++++++++++--
6 files changed, 165 insertions(+), 35 deletions(-)

diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/ext/Context.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/ext/Context.kt @@ -7,7 +7,6 @@ package org.mozilla.fenix.ext import android.app.Activity import android.content.Context import android.content.Intent -import android.content.pm.PackageManager import android.content.res.Configuration import android.content.res.Resources import android.provider.Settings @@ -20,7 +19,6 @@ import androidx.annotation.StringRes import mozilla.components.compose.base.theme.layout.AcornWindowSize import mozilla.components.support.base.log.logger.Logger import mozilla.components.support.locale.LocaleManager -import mozilla.components.support.utils.ext.packageManagerCompatHelper import org.mozilla.fenix.FenixApplication import org.mozilla.fenix.R import org.mozilla.fenix.components.Components @@ -217,19 +215,3 @@ fun Context.isToolbarAtBottom() = * @return The pixel size corresponding to the given dimension resource. */ fun Context.pixelSizeFor(@DimenRes resId: Int) = resources.getDimensionPixelSize(resId) - -/** - * Returns the installation time of this application (in milliseconds). - * - * @param logger Used to log a warning if package information cannot be retrieved. - * @return The installation time in milliseconds since epoch, or `0L` if unavailable. - */ -fun Context.getApplicationInstalledTime(logger: Logger): Long = try { - packageManagerCompatHelper.getPackageInfoCompat(packageName, 0).firstInstallTime -} catch (e: PackageManager.NameNotFoundException) { - logger.warn("Unable to retrieve package info for $packageName", e) - 0L -} catch (e: UnsupportedOperationException) { - logger.warn("Unable to retrieve package info for $packageName", e) - 0L -} diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/termsofuse/GetApplicationInstalledTime.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/termsofuse/GetApplicationInstalledTime.kt @@ -0,0 +1,28 @@ +/* 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.termsofuse + +import android.content.pm.PackageManager +import mozilla.components.support.base.log.logger.Logger +import mozilla.components.support.utils.ext.PackageManagerCompatHelper + +/** + * Returns the installation time of this application (in milliseconds). + * + * @return The installation time in milliseconds since epoch, or `0L` if unavailable. + */ +fun getApplicationInstalledTime( + packageManagerCompatHelper: PackageManagerCompatHelper, + packageName: String, + logger: Logger, +): Long = try { + packageManagerCompatHelper.getPackageInfoCompat(packageName, 0).firstInstallTime +} catch (e: PackageManager.NameNotFoundException) { + logger.warn("Unable to retrieve package info for $packageName", e) + 0L +} catch (e: UnsupportedOperationException) { + logger.warn("Unable to retrieve package info for $packageName", e) + 0L +} diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/utils/Settings.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/utils/Settings.kt @@ -34,6 +34,8 @@ import mozilla.components.support.ktx.android.content.stringPreference import mozilla.components.support.ktx.android.content.stringSetPreference import mozilla.components.support.locale.LocaleManager import mozilla.components.support.utils.BrowsersCache +import mozilla.components.support.utils.ext.PackageManagerCompatHelper +import mozilla.components.support.utils.ext.packageManagerCompatHelper import org.mozilla.experiments.nimbus.NimbusEventStore import org.mozilla.fenix.BuildConfig import org.mozilla.fenix.Config @@ -51,7 +53,6 @@ import org.mozilla.fenix.debugsettings.addresses.SharedPrefsAddressesDebugRegion import org.mozilla.fenix.ext.TALL_SCREEN_HEIGHT_DP import org.mozilla.fenix.ext.WIDE_SCREEN_WIDTH_DP import org.mozilla.fenix.ext.components -import org.mozilla.fenix.ext.getApplicationInstalledTime import org.mozilla.fenix.ext.getPreferenceKey import org.mozilla.fenix.ext.pixelSizeFor import org.mozilla.fenix.home.pocket.ContentRecommendationsFeatureHelper @@ -74,6 +75,7 @@ import org.mozilla.fenix.settings.sitepermissions.AUTOPLAY_BLOCK_ALL import org.mozilla.fenix.settings.sitepermissions.AUTOPLAY_BLOCK_AUDIBLE import org.mozilla.fenix.tabstray.DefaultTabManagementFeatureHelper import org.mozilla.fenix.termsofuse.TOU_VERSION +import org.mozilla.fenix.termsofuse.getApplicationInstalledTime import org.mozilla.fenix.wallpapers.Wallpaper import java.security.InvalidParameterException import java.util.UUID @@ -85,10 +87,15 @@ private const val AUTOPLAY_USER_SETTING = "AUTOPLAY_USER_SETTING" * A simple wrapper for SharedPreferences that makes reading preference a little bit easier. * * @param appContext Reference to application context. + * @param packageName Package name of the application. + * @param packageManagerCompatHelper Helper for accessing [android.content.pm.PackageManager] methods. */ @Suppress("LargeClass", "TooManyFunctions") -class Settings(private val appContext: Context) : PreferencesHolder { - +class Settings( + private val appContext: Context, + private val packageName: String = appContext.packageName, + private val packageManagerCompatHelper: PackageManagerCompatHelper = appContext.packageManagerCompatHelper, +) : PreferencesHolder { companion object { const val FENIX_PREFERENCES = "fenix_preferences" @@ -579,21 +586,20 @@ class Settings(private val appContext: Context) : PreferencesHolder { */ var termsOfUseAcceptedTimeInMillis by longPreference( key = appContext.getPreferenceKey(R.string.pref_key_terms_accepted_date), - default = { if (hasAcceptedTermsOfService) applicationInstalledTime else 0L }, + default = { + if (hasAcceptedTermsOfService) { + getApplicationInstalledTime( + packageManagerCompatHelper = packageManagerCompatHelper, + packageName = packageName, + logger = logger, + ) + } else { + 0L + } + }, ) /** - * Temporary testing helper to set the date the user accepted the Terms of Use. - * - * Will be addressed in a more permanent refactor as part of - * https://bugzilla.mozilla.org/show_bug.cgi?id=1993949. - * - * ⚠️ Only mutate from tests. - */ - @VisibleForTesting - internal var applicationInstalledTime = appContext.getApplicationInstalledTime(logger) - - /** * The version of the Terms of Use that the user has accepted. */ var termsOfUseAcceptedVersion by intPreference( diff --git a/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/termsofuse/GetApplicationInstalledTimeTest.kt b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/termsofuse/GetApplicationInstalledTimeTest.kt @@ -0,0 +1,68 @@ +/* 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.termsofuse + +import android.content.pm.PackageInfo +import android.content.pm.PackageManager +import mozilla.components.support.base.log.logger.Logger +import org.junit.Assert.assertEquals +import org.junit.Test +import org.mozilla.fenix.utils.FakePackageManagerCompatHelper + +class GetApplicationInstalledTimeTest { + + @Test + fun `WHEN getPackageInfoCompat returns a time THEN getApplicationInstalledTime returns the same time`() { + val installTime = 12345L + + val result = getApplicationInstalledTime( + packageManagerCompatHelper = FakePackageManagerCompatHelper( + packageInfo = PackageInfo().apply { + firstInstallTime = installTime + }, + ), + packageName = "UNUSED", + logger = Logger(), + ) + + assertEquals(installTime, result) + } + + @Test + fun `WHEN getPackageInfoCompat throws NameNotFoundException THEN getApplicationInstalledTime returns 0`() { + val installTime = 12345L + + val result = getApplicationInstalledTime( + packageManagerCompatHelper = FakePackageManagerCompatHelper( + packageInfo = PackageInfo().apply { + firstInstallTime = installTime + }, + getPackageInfoThrowable = PackageManager.NameNotFoundException(), + ), + packageName = "UNUSED", + logger = Logger(), + ) + + assertEquals(0, result) + } + + @Test + fun `WHEN getPackageInfoCompat throws UnsupportedOperationException THEN getApplicationInstalledTime returns 0`() { + val installTime = 12345L + + val result = getApplicationInstalledTime( + packageManagerCompatHelper = FakePackageManagerCompatHelper( + packageInfo = PackageInfo().apply { + firstInstallTime = installTime + }, + getPackageInfoThrowable = UnsupportedOperationException(), + ), + packageName = "UNUSED", + logger = Logger(), + ) + + assertEquals(0, result) + } +} diff --git a/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/utils/FakePackageManagerCompatHelper.kt b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/utils/FakePackageManagerCompatHelper.kt @@ -0,0 +1,31 @@ +/* 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.utils + +import android.content.Intent +import android.content.pm.ApplicationInfo +import android.content.pm.PackageInfo +import android.content.pm.ResolveInfo +import mozilla.components.support.utils.ext.PackageManagerCompatHelper +import java.util.Collections.emptyList + +class FakePackageManagerCompatHelper( + val packageInfo: PackageInfo = PackageInfo(), + val getPackageInfoThrowable: Throwable? = null, + val applicationInfo: ApplicationInfo = ApplicationInfo(), +) : PackageManagerCompatHelper { + override fun queryIntentActivitiesCompat(intent: Intent, flag: Int): MutableList<ResolveInfo> = + emptyList() + + override fun resolveActivityCompat(intent: Intent, flag: Int): ResolveInfo? = null + + override fun getPackageInfoCompat(packageName: String, flag: Int): PackageInfo { + getPackageInfoThrowable?.let { throw it } + + return packageInfo + } + + override fun getApplicationInfoCompat(packageName: String, flag: Int) = applicationInfo +} diff --git a/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/utils/SettingsTest.kt b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/utils/SettingsTest.kt @@ -4,6 +4,7 @@ package org.mozilla.fenix.utils +import android.content.pm.PackageInfo import androidx.core.content.edit import io.mockk.every import io.mockk.spyk @@ -1273,20 +1274,34 @@ class SettingsTest { @Test fun `WHEN user has accepted the ToU THEN termsOfUseAcceptedTimeInMillis returns the app installed time`() { val installTime = 12345L - settings.applicationInstalledTime = installTime + val settings = Settings( + appContext = testContext, + packageName = "test", + packageManagerCompatHelper = FakePackageManagerCompatHelper( + packageInfo = PackageInfo().apply { firstInstallTime = installTime }, + ), + ) settings.hasAcceptedTermsOfService = true val result = settings.termsOfUseAcceptedTimeInMillis + assertEquals(installTime, result) } @Test fun `WHEN user has not accepted the ToU THEN termsOfUseAcceptedTimeInMillis returns 0L`() { val installTime = 12345L - settings.applicationInstalledTime = installTime + val settings = Settings( + appContext = testContext, + packageName = "test", + packageManagerCompatHelper = FakePackageManagerCompatHelper( + packageInfo = PackageInfo().apply { firstInstallTime = installTime }, + ), + ) settings.hasAcceptedTermsOfService = false val result = settings.termsOfUseAcceptedTimeInMillis + assertEquals(0L, result) }