commit 265dbba6a0b0a04f2123a2008d7fa9b8308c5d27 parent 5e73078aa58e83630ee8f6632b16832344d2f07e Author: Matthew Finkel <sysrqb@torproject.org> Date: Wed, 9 Sep 2020 22:59:30 +0000 [android] Modify UI/UX Bug 40015: Modify Home menu Bug 40016: Hide unwanted Settings Bug 40016: Modify Default toolbar menu Bug 40016: Add Donate settings button Bug 40016: Move Allow Screenshots under Advanced Bug 40016: Don't install WebCompat webext Bug 40016: Don't onboard Search Suggestions Bug 40094: Do not use MasterPasswordTipProvider in HomeFragment Bug 40095: Hide "Sign in to sync" in bookmarks Bug 40031: Hide Mozilla-specific items on About page Bug 40063: Do not sort search engines alphabetically Bug 40141: Hide EME site permission Bug 40166: Hide "Normal" tab (again) and Sync tab in TabTray Bug 40167: Hide "Save to Collection" in menu Bug 40172: Find the Quit button Bug 40186: Hide Credit Cards in Settings Bug 40198: Spoof English toggle now overlaps with locale list Diffstat:
49 files changed, 1408 insertions(+), 391 deletions(-)
diff --git a/mobile/android/android-components/components/feature/awesomebar/src/main/java/mozilla/components/feature/awesomebar/provider/SessionAutocompleteProvider.kt b/mobile/android/android-components/components/feature/awesomebar/src/main/java/mozilla/components/feature/awesomebar/provider/SessionAutocompleteProvider.kt @@ -36,7 +36,7 @@ class SessionAutocompleteProvider( val tabUrl = store.state.tabs .firstOrNull { - !it.content.private && doesUrlStartsWithText(it.content.url, query) + /* !it.content.private && */ doesUrlStartsWithText(it.content.url, query) } ?.content?.url ?: return null diff --git a/mobile/android/android-components/components/feature/awesomebar/src/main/java/mozilla/components/feature/awesomebar/provider/SessionSuggestionProvider.kt b/mobile/android/android-components/components/feature/awesomebar/src/main/java/mozilla/components/feature/awesomebar/provider/SessionSuggestionProvider.kt @@ -52,12 +52,12 @@ class SessionSuggestionProvider( val searchWords = searchText.split(" ") distinctTabs.filter { item -> - !item.content.private && + // tor-browser#43788: Show "Switch to tab" suggestions also on private tabs. searchWords.all { item.contains(it) } && resultsUriFilter?.invoke(item.content.url.toUri()) != false && shouldIncludeSelectedTab(state, item) }.forEach { item -> - val iconRequest = icons?.loadIcon(IconRequest(url = item.content.url, waitOnNetworkLoad = false)) + val iconRequest = icons?.loadIcon(IconRequest(url = item.content.url, isPrivate = item.content.private, waitOnNetworkLoad = false)) suggestions.add( AwesomeBar.Suggestion( provider = this, diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/browser/BrowserFragment.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/browser/BrowserFragment.kt @@ -152,7 +152,7 @@ class BrowserFragment : BaseBrowserFragment(), UserInteractionHandler { view = view, ) - if (context.settings().shouldShowOpenInAppCfr) { + if (false) { // context.settings().shouldShowOpenInAppCfr openInAppOnboardingObserver.set( feature = OpenInAppOnboardingObserver( context = context, diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/browser/OpenInAppOnboardingObserver.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/browser/OpenInAppOnboardingObserver.kt @@ -64,7 +64,7 @@ class OpenInAppOnboardingObserver( currentUrl = tab.content.url } else { // Loading state has changed - maybeShowOpenInAppBanner(tab.content.url, tab.content.loading) +// maybeShowOpenInAppBanner(tab.content.url, tab.content.loading) } } } diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/menu/middleware/MenuNavigationMiddleware.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/menu/middleware/MenuNavigationMiddleware.kt @@ -148,7 +148,7 @@ class MenuNavigationMiddleware( ) is MenuAction.Navigate.ReleaseNotes -> openToBrowser( - BrowserNavigationParams(url = SupportUtils.WHATS_NEW_URL), + BrowserNavigationParams(url = SupportUtils.getTorWhatsNewUrl()), ) is MenuAction.Navigate.EditBookmark -> { diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarCFRPresenter.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarCFRPresenter.kt @@ -98,30 +98,31 @@ class BrowserToolbarCFRPresenter( } } - when (getCFRToShow()) { - ToolbarCFR.COOKIE_BANNERS -> { - scope = browserStore.flowScoped { flow -> - flow.mapNotNull { it.findCustomTabOrSelectedTab(customTabId) } - .ifAnyChanged { tab -> - arrayOf( - tab.cookieBanner, - ) - } - .filter { - it.content.private && it.cookieBanner == CookieBannerHandlingStatus.HANDLED - } - .collect { - scope?.cancel() - settings.shouldShowCookieBannersCFR = false - showCookieBannersCFR() - } - } - } - - ToolbarCFR.NONE -> { - // no-op - } - } + // Removed for tor-browser#42089: Remove ability to submit site support requests + // when (getCFRToShow()) { + // ToolbarCFR.COOKIE_BANNERS -> { + // scope = browserStore.flowScoped { flow -> + // flow.mapNotNull { it.findCustomTabOrSelectedTab(customTabId) } + // .ifAnyChanged { tab -> + // arrayOf( + // tab.cookieBanner, + // ) + // } + // .filter { + // it.content.private && it.cookieBanner == CookieBannerHandlingStatus.HANDLED + // } + // .collect { + // scope?.cancel() + // settings.shouldShowCookieBannersCFR = false + // showCookieBannersCFR() + // } + // } + // } + + // ToolbarCFR.NONE -> { + // // no-op + // } + // } } private fun getCFRToShow(): ToolbarCFR = when { diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/toolbar/DefaultToolbarMenu.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/toolbar/DefaultToolbarMenu.kt @@ -74,7 +74,6 @@ open class DefaultToolbarMenu( private var isCurrentUrlBookmarked = false private var isBookmarkedJob: Job? = null - private val shouldDeleteDataOnQuit = context.settings().shouldDeleteBrowsingDataOnQuit private val shouldUseBottomToolbar = context.settings().shouldUseBottomToolbar private val shouldShowTopSites = context.settings().showTopSitesFeature private val accountManager = FenixAccountManager(context) @@ -310,14 +309,6 @@ open class DefaultToolbarMenu( onItemTapped.invoke(ToolbarMenu.Item.OpenInApp) } - private val addToHomeScreenItem = BrowserMenuImageText( - label = context.getString(R.string.browser_menu_add_to_homescreen), - imageResource = iconsR.drawable.mozac_ic_add_to_homescreen_24, - iconTintColorResource = primaryTextColor(), - isCollapsingMenuLimit = true, - ) { - onItemTapped.invoke(ToolbarMenu.Item.AddToHomeScreen) - } private val addAppToHomeScreenItem = BrowserMenuImageText( label = context.getString(R.string.browser_menu_add_app_to_homescreen), @@ -346,14 +337,6 @@ open class DefaultToolbarMenu( }, ) - private val saveToCollectionItem = BrowserMenuImageText( - label = context.getString(R.string.browser_menu_save_to_collection_2), - imageResource = R.drawable.ic_tab_collection, - iconTintColorResource = primaryTextColor(), - ) { - onItemTapped.invoke(ToolbarMenu.Item.SaveToCollection) - } - private val printPageItem = BrowserMenuImageText( label = context.getString(R.string.menu_print), imageResource = R.drawable.ic_print, @@ -411,14 +394,6 @@ open class DefaultToolbarMenu( onItemTapped.invoke(ToolbarMenu.Item.Quit) } - private fun syncMenuItem(): BrowserMenuItem { - return BrowserMenuSignIn(primaryTextColor()) { - onItemTapped.invoke( - ToolbarMenu.Item.SyncAccount(accountManager.accountState), - ) - } - } - @VisibleForTesting(otherwise = PRIVATE) val coreMenuItems by lazy { val menuItems = @@ -431,29 +406,18 @@ open class DefaultToolbarMenu( downloadsItem, passwordsItem, extensionsItem, - syncMenuItem(), BrowserMenuDivider(), findInPageItem, translationsItem.apply { visible = ::shouldShowTranslations }, desktopSiteItem.apply { visible = { store.state.selectedTab?.content?.isPdf == false } }, // openInRegularTabItem.apply { visible = ::shouldShowOpenInRegularTab }, customizeReaderView.apply { visible = ::shouldShowReaderViewCustomization }, - openInApp.apply { visible = ::shouldShowOpenInApp }, BrowserMenuDivider(), - addToHomeScreenItem.apply { visible = ::canAddToHomescreen }, addAppToHomeScreenItem.apply { visible = ::canAddAppToHomescreen }, - if (shouldShowTopSites) addRemoveTopSitesItem else null, - saveToCollectionItem, - if (FxNimbus.features.print.value().browserPrintEnabled && - !context.isAndroidAutomotiveAvailable() - ) { - printPageItem - } else { - null - }, + printPageItem, BrowserMenuDivider(), settingsItem, - if (shouldDeleteDataOnQuit) deleteDataOnQuit else null, + deleteDataOnQuit, if (shouldUseBottomToolbar) BrowserMenuDivider() else null, if (shouldUseBottomToolbar) menuToolbar else null, ) diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/customtabs/CustomTabToolbarMenu.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/customtabs/CustomTabToolbarMenu.kt @@ -126,7 +126,7 @@ class CustomTabToolbarMenu( BrowserMenuDivider().apply { visible = { !isSandboxCustomTab } }, desktopMode.apply { visible = { session?.content?.isPdf == false } }, findInPage, - openInApp.apply { visible = ::shouldShowOpenInApp }, + // openInApp.apply { visible = ::shouldShowOpenInApp }, openInFenix.apply { visible = { !isSandboxCustomTab } }, BrowserMenuDivider(), menuToolbar, diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt @@ -71,6 +71,7 @@ import mozilla.components.support.utils.KeyboardState import mozilla.components.support.utils.keyboardAsState import mozilla.telemetry.glean.private.NoExtras import org.mozilla.fenix.BrowserDirection +import org.mozilla.fenix.BuildConfig import org.mozilla.fenix.GleanMetrics.HomeScreen import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.NavGraphDirections @@ -179,6 +180,9 @@ import org.mozilla.fenix.utils.showAddSearchWidgetPromptIfSupported import org.mozilla.fenix.wallpapers.Wallpaper import java.lang.ref.WeakReference +import org.mozilla.fenix.components.toolbar.ToolbarPosition +import org.mozilla.fenix.tor.TorHomePage + @Suppress("TooManyFunctions", "LargeClass") class HomeFragment : Fragment() { private val args by navArgs<HomeFragmentArgs>() @@ -620,7 +624,7 @@ class HomeFragment : Fragment() { listenForMicrosurveyMessage(requireContext()) } - initComposeHomepage() + initComposeTorHomePageView() disableAppBarDragging() @@ -1014,6 +1018,17 @@ class HomeFragment : Fragment() { ) } + private fun initComposeTorHomePageView() { + binding.torHomepageView.apply { + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) + setContent { + TorHomePage( + toolBarAtTop = settings().toolbarPosition == ToolbarPosition.TOP + ) + } + } + } + private fun initComposeHomepage() { binding.homeAppBarContent.isVisible = false diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/home/HomeMenu.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/home/HomeMenu.kt @@ -29,6 +29,7 @@ import org.mozilla.fenix.components.accounts.AccountState import org.mozilla.fenix.components.accounts.FenixAccountManager import org.mozilla.fenix.components.toolbar.BrowserMenuSignIn import org.mozilla.fenix.ext.components +import org.mozilla.fenix.ext.settings import org.mozilla.fenix.nimbus.FxNimbus import org.mozilla.fenix.theme.ThemeManager import org.mozilla.fenix.whatsnew.WhatsNew @@ -56,7 +57,7 @@ class HomeMenu( object WhatsNew : Item() object Help : Item() - object CustomizeHome : Item() + // object CustomizeHome : Item() object Settings : Item() object Quit : Item() object ReconnectSync : Item() @@ -104,7 +105,7 @@ class HomeMenu( } private fun coreMenuItems(): List<BrowserMenuItem> { - val settings = context.components.settings + // val settings = context.components.settings val bookmarksItem = BrowserMenuImageText( context.getString(R.string.library_bookmarks), @@ -138,13 +139,6 @@ class HomeMenu( onItemTapped.invoke(Item.Passwords) } - val extensionsItem = BrowserMenuImageText( - context.getString(R.string.browser_menu_extensions), - R.drawable.ic_addons_extensions, - primaryTextColor, - ) { - onItemTapped.invoke(Item.Extensions) - } val whatsNewItem = BrowserMenuHighlightableItem( context.getString(R.string.browser_menu_whats_new), @@ -166,19 +160,9 @@ class HomeMenu( onItemTapped.invoke(Item.Help) } - val customizeHomeItem = BrowserMenuImageText( - context.getString(R.string.browser_menu_customize_home_1), - R.drawable.ic_customize, - primaryTextColor, - ) { - onItemTapped.invoke(Item.CustomizeHome) - AppMenu.customizeHomepage.record(NoExtras()) - } - // Use nimbus to set the icon and title. - val nimbusValidation = FxNimbus.features.nimbusValidation.value() val settingsItem = BrowserMenuImageText( - nimbusValidation.settingsTitle, + context.getString(R.string.browser_menu_settings), iconsR.drawable.mozac_ic_settings_24, primaryTextColor, ) { @@ -200,23 +184,19 @@ class HomeMenu( // We will show syncSignIn item when the accountAuth item: // 1. is not needed or // 2. it is needed, but the account manager is not available yet - val syncSignInMenuItem = if (accountAuthItem == null) syncSignInMenuItem() else null val menuItems = listOfNotNull( bookmarksItem, - historyItem, + if (context.settings().shouldDisableNormalMode) null else historyItem, downloadsItem, passwordsItem, - extensionsItem, - syncSignInMenuItem, accountAuthItem, BrowserMenuDivider(), BrowserMenuDivider(), whatsNewItem, helpItem, - customizeHomeItem, settingsItem, - if (settings.shouldDeleteBrowsingDataOnQuit) quitItem else null, + quitItem ).also { items -> items.getHighlight()?.let { onHighlightPresent(it) } } diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/home/HomeMenuView.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/home/HomeMenuView.kt @@ -124,14 +124,14 @@ class HomeMenuView( HomeFragmentDirections.actionGlobalSettingsFragment(), ) } - HomeMenu.Item.CustomizeHome -> { - HomeScreen.customizeHomeClicked.record(NoExtras()) - - navController.nav( - R.id.homeFragment, - HomeFragmentDirections.actionGlobalHomeSettingsFragment(), - ) - } +// HomeMenu.Item.CustomizeHome -> { +// HomeScreen.customizeHomeClicked.record(NoExtras()) +// +// navController.nav( +// R.id.homeFragment, +// HomeFragmentDirections.actionGlobalHomeSettingsFragment(), +// ) +// } is HomeMenu.Item.SyncAccount -> { navController.nav( R.id.homeFragment, @@ -181,10 +181,7 @@ class HomeMenuView( HomeFragmentDirections.actionGlobalBrowser(), ) fenixBrowserUseCases.loadUrlOrSearch( - searchTermOrURL = SupportUtils.getSumoURLForTopic( - context = context, - topic = SupportUtils.SumoTopic.HELP, - ), + searchTermOrURL = SupportUtils.getTorHelpPageUrl(), newTab = true, private = homeActivity.browsingModeManager.mode.isPrivate, ) @@ -198,7 +195,7 @@ class HomeMenuView( HomeFragmentDirections.actionGlobalBrowser(), ) fenixBrowserUseCases.loadUrlOrSearch( - searchTermOrURL = SupportUtils.WHATS_NEW_URL, + searchTermOrURL = SupportUtils.getTorWhatsNewUrl(), newTab = true, private = homeActivity.browsingModeManager.mode.isPrivate, ) diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/search/SearchDialogFragment.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/search/SearchDialogFragment.kt @@ -488,6 +488,13 @@ class SearchDialogFragment : AppCompatDialogFragment(), UserInteractionHandler { searchSuggestionHintBinding.title.text = getString(R.string.search_suggestions_onboarding_title) + + // Hide Search Suggestions prompt and disable + inflated.visibility = View.GONE + requireContext().settings().also { + it.shouldShowSearchSuggestionsInPrivate = false + it.showSearchSuggestionsInPrivateOnboardingFinished = true + } } binding.searchSuggestionsHint.setOnInflateListener((stubListener)) diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/search/awesomebar/SearchSuggestionsProvidersBuilder.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/search/awesomebar/SearchSuggestionsProvidersBuilder.kt @@ -78,7 +78,7 @@ class SearchSuggestionsProvidersBuilder( components.core.icons, engineForSpeculativeConnects, showEditSuggestion = false, - suggestionsHeader = suggestionsStringsProvider.firefoxSuggestHeader, + // suggestionsHeader = suggestionsStringsProvider.firefoxSuggestHeader, ) defaultCombinedHistoryProvider = @@ -90,7 +90,7 @@ class SearchSuggestionsProvidersBuilder( engine = engineForSpeculativeConnects, maxNumberOfSuggestions = METADATA_SUGGESTION_LIMIT, showEditSuggestion = false, - suggestionsHeader = suggestionsStringsProvider.firefoxSuggestHeader, + // suggestionsHeader = suggestionsStringsProvider.firefoxSuggestHeader, ) val searchBitmap = suggestionIconProvider.getSearchIconBitmap() @@ -226,12 +226,12 @@ class SearchSuggestionsProvidersBuilder( } } - if (!browsingModeManager.mode.isPrivate && state.showAllSessionSuggestions) { + if (/* !browsingModeManager.mode.isPrivate && */ state.showAllSessionSuggestions) { // Unlike other providers, we don't exclude sponsored suggestions for open tabs. providersToAdd.add(getLocalTabsProvider()) } - if (!browsingModeManager.mode.isPrivate && state.showSessionSuggestionsForCurrentEngine) { + if (/* !browsingModeManager.mode.isPrivate && */ state.showSessionSuggestionsForCurrentEngine) { getFilterForCurrentEngineResults(state)?.let { providersToAdd.add(getLocalTabsProvider(it)) } @@ -244,7 +244,7 @@ class SearchSuggestionsProvidersBuilder( loadUrlUseCase = loadUrlUseCase, includeSponsoredSuggestions = state.showSponsoredSuggestions, includeNonSponsoredSuggestions = state.showNonSponsoredSuggestions, - suggestionsHeader = suggestionsStringsProvider.firefoxSuggestHeader, + // suggestionsHeader = suggestionsStringsProvider.firefoxSuggestHeader, sponsoredSuggestionDescription = suggestionsStringsProvider.getSponsoredSuggestionDescription(), contextId = components.settings.contileContextId, scorer = FxSuggestionExperimentScorer(), @@ -254,7 +254,7 @@ class SearchSuggestionsProvidersBuilder( loadUrlUseCase = loadUrlUseCase, includeSponsoredSuggestions = state.showSponsoredSuggestions, includeNonSponsoredSuggestions = state.showNonSponsoredSuggestions, - suggestionsHeader = suggestionsStringsProvider.firefoxSuggestHeader, + // suggestionsHeader = suggestionsStringsProvider.firefoxSuggestHeader, sponsoredSuggestionDescription = suggestionsStringsProvider.getSponsoredSuggestionDescription(), contextId = components.settings.contileContextId, ) @@ -301,7 +301,7 @@ class SearchSuggestionsProvidersBuilder( engine = engineForSpeculativeConnects, maxNumberOfSuggestions = METADATA_SUGGESTION_LIMIT, showEditSuggestion = false, - suggestionsHeader = suggestionsStringsProvider.firefoxSuggestHeader, + // suggestionsHeader = suggestionsStringsProvider.firefoxSuggestHeader, resultsUriFilter = filter::shouldIncludeUri, ) } else { @@ -316,7 +316,7 @@ class SearchSuggestionsProvidersBuilder( engine = engineForSpeculativeConnects, maxNumberOfSuggestions = METADATA_SUGGESTION_LIMIT, showEditSuggestion = false, - suggestionsHeader = suggestionsStringsProvider.firefoxSuggestHeader, + // suggestionsHeader = suggestionsStringsProvider.firefoxSuggestHeader, resultsUriFilter = filter::shouldIncludeUri, ) } else { @@ -428,7 +428,7 @@ class SearchSuggestionsProvidersBuilder( suggestionIconProvider.getMobileIconDrawable(), suggestionIconProvider.getTabletIconDrawable(), ), - suggestionsHeader = suggestionsStringsProvider.firefoxSuggestHeader, + // suggestionsHeader = suggestionsStringsProvider.firefoxSuggestHeader, resultsUrlFilter = filter?.let { it::shouldIncludeUrl }, ) } @@ -450,7 +450,7 @@ class SearchSuggestionsProvidersBuilder( components.core.icons, suggestionIconProvider.getLocalTabIconDrawable(), excludeSelectedSession = !includeSelectedTab, - suggestionsHeader = suggestionsStringsProvider.firefoxSuggestHeader, + // suggestionsHeader = suggestionsStringsProvider.firefoxSuggestHeader, switchToTabDescription = suggestionsStringsProvider.getSwitchToTabDescriptionString(), resultsUriFilter = filter?.let { it::shouldIncludeUri }, ) @@ -474,7 +474,7 @@ class SearchSuggestionsProvidersBuilder( indicatorIcon = suggestionIconProvider.getBookmarkIconDrawable(), engine = engineForSpeculativeConnects, showEditSuggestion = false, - suggestionsHeader = suggestionsStringsProvider.firefoxSuggestHeader, + // suggestionsHeader = suggestionsStringsProvider.firefoxSuggestHeader, resultsUriFilter = filter?.let { it::shouldIncludeUri }, ) } diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt @@ -42,6 +42,7 @@ import mozilla.components.support.base.feature.ViewBoundFeatureWrapper import mozilla.components.support.ktx.android.view.showKeyboard import mozilla.components.ui.widgets.withCenterAlignedButtons import mozilla.telemetry.glean.private.NoExtras +import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.Config import org.mozilla.fenix.FeatureFlags import org.mozilla.fenix.GleanMetrics.Addons @@ -50,6 +51,7 @@ import org.mozilla.fenix.GleanMetrics.Events import org.mozilla.fenix.GleanMetrics.SettingsSearch import org.mozilla.fenix.GleanMetrics.TrackingProtection import org.mozilla.fenix.GleanMetrics.Translations +import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R import org.mozilla.fenix.components.Components import org.mozilla.fenix.components.accounts.FenixFxAEntryPoint @@ -511,6 +513,15 @@ class SettingsFragment : PreferenceFragmentCompat() { SettingsFragmentDirections.actionSettingsFragmentToAboutFragment() } + resources.getString(R.string.pref_key_donate) -> { + (activity as HomeActivity).openToBrowserAndLoad( + searchTermOrURL = SupportUtils.DONATE_URL, + newTab = true, + from = BrowserDirection.FromSettings + ) + null + } + // Only displayed when secret settings are enabled resources.getString(R.string.pref_key_debug_settings) -> { SettingsFragmentDirections.actionSettingsFragmentToSecretSettingsFragment() diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/SupportUtils.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/SupportUtils.kt @@ -20,13 +20,16 @@ import java.net.URLEncoder import java.util.Locale import com.google.android.material.R as materialR +@Suppress("TooManyFunctions") object SupportUtils { const val RATE_APP_URL = "market://details?id=" + BuildConfig.APPLICATION_ID const val FENIX_PLAY_STORE_URL = "https://play.google.com/store/apps/details?id=${BuildConfig.APPLICATION_ID}" const val GOOGLE_URL = "https://www.google.com/" const val GOOGLE_US_URL = "https://www.google.com/webhp?client=firefox-b-1-m&channel=ts" const val GOOGLE_XX_URL = "https://www.google.com/webhp?client=firefox-b-m&channel=ts" - const val WHATS_NEW_URL = "https://www.mozilla.org/firefox/android/notes" + // const val WHATS_NEW_URL = "https://www.torproject.org/releases/" + const val DONATE_URL = "https://donate.torproject.org/" + const val TB_MANUAL_URL = "https://tb-manual.torproject.org/mobile-tor" const val FXACCOUNT_SUMO_URL = "https://support.mozilla.org/kb/access-mozilla-services-firefox-account" const val ANDROID_SUPPORT_SUMO_URL = "mzl.la/AndroidSupport" @@ -114,6 +117,21 @@ object SupportUtils { return "https://support.mozilla.org/$langTag/kb/$escapedTopic" } + fun getTorHelpPageUrl(): String { + return TB_MANUAL_URL + } + + fun getTorWhatsNewUrl(): String { + val versionNumber = BuildConfig.VERSION_NAME.substringBefore(' ') // e.g. "13.5a5" + if (versionNumber.isEmpty()) { + return "https://blog.torproject.org/" + } + val alpha: String = if (versionNumber.contains('a')) "alpha-" else "" + val versionNumberNoDecimals: String = + versionNumber.split('.').joinToString("") // e.g. "135a5" + return "https://blog.torproject.org/new-${alpha}release-tor-browser-${versionNumberNoDecimals}/" // e.g. "https://blog.torproject.org/new-alpha-release-tor-browser-135a5/ + } + fun getMozillaPageUrl(page: MozillaPage, locale: Locale = Locale.getDefault()): String { val path = page.path val langTag = getLanguageTag(locale) diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/about/AboutFragment.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/about/AboutFragment.kt @@ -194,13 +194,13 @@ class AboutFragment( } private fun populateAboutList(): List<AboutPageItem> { - val context = requireContext() + //val context = requireContext() return listOf( AboutPageItem( AboutItem.ExternalLink( WHATS_NEW, - SupportUtils.WHATS_NEW_URL, + SupportUtils.getTorWhatsNewUrl(), ), // Note: Fenix only has release notes for 'Release' versions, NOT 'Beta' & 'Nightly'. getString(R.string.about_whats_new, getString(R.string.firefox)), @@ -208,28 +208,28 @@ class AboutFragment( AboutPageItem( AboutItem.ExternalLink( SUPPORT, - SupportUtils.getSumoURLForTopic(context, SupportUtils.SumoTopic.HELP), + SupportUtils.getTorHelpPageUrl() ), getString(R.string.about_support), ), - AboutPageItem( - AboutItem.Crashes, - getString(R.string.about_crashes), - ), - AboutPageItem( - AboutItem.ExternalLink( - PRIVACY_NOTICE, - SupportUtils.getMozillaPageUrl(SupportUtils.MozillaPage.PRIVACY_NOTICE), - ), - getString(R.string.about_privacy_notice), - ), - AboutPageItem( - AboutItem.ExternalLink( - RIGHTS, - SupportUtils.getSumoURLForTopic(context, SupportUtils.SumoTopic.YOUR_RIGHTS), - ), - getString(R.string.about_know_your_rights), - ), + //AboutPageItem( + // AboutItem.Crashes, + // getString(R.string.about_crashes), + //), + //AboutPageItem( + // AboutItem.ExternalLink( + // PRIVACY_NOTICE, + // SupportUtils.getMozillaPageUrl(SupportUtils.MozillaPage.PRIVACY_NOTICE), + // ), + // getString(R.string.about_privacy_notice), + //), + //AboutPageItem( + // AboutItem.ExternalLink( + // RIGHTS, + // SupportUtils.getSumoURLForTopic(context, SupportUtils.SumoTopic.YOUR_RIGHTS), + // ), + // getString(R.string.about_know_your_rights), + //), AboutPageItem( AboutItem.ExternalLink(LICENSING_INFO, ABOUT_LICENSE_URL), getString(R.string.about_licensing_information), diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/account/AccountUiView.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/account/AccountUiView.kt @@ -84,7 +84,7 @@ class AccountUiView( // Signed-out. } else { - preferenceSignIn.isVisible = true + preferenceSignIn.isVisible = false preferenceFirefoxAccount.isVisible = false preferenceFirefoxAccountAuthError.isVisible = false accountPreferenceCategory.isVisible = false diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/logins/view/SavedLoginsListView.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/logins/view/SavedLoginsListView.kt @@ -64,7 +64,7 @@ class SavedLoginsListView( } else { binding.progressBar.isVisible = false binding.savedLoginsList.isVisible = state.loginList.isNotEmpty() - binding.savedPasswordsEmptyView.isVisible = state.loginList.isEmpty() + binding.savedPasswordsEmptyView.isVisible = false } loginsAdapter.submitList(state.filteredItems) { // Reset scroll position to the first item after submitted list was committed. diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/quicksettings/QuickSettingsSheetDialogFragment.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/quicksettings/QuickSettingsSheetDialogFragment.kt @@ -138,7 +138,8 @@ class QuickSettingsSheetDialogFragment : FenixDialogFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - observeTrackersChange(requireComponents.core.store) +// Removed as part of Bug_42115: Enhanced Tracking Protection can still be enabled +// observeTrackersChange(requireComponents.core.store) consumeFrom(quickSettingsStore) { websiteInfoView.update(it.webInfoState) websitePermissionsView.update(it.websitePermissionsState) @@ -197,34 +198,36 @@ class QuickSettingsSheetDialogFragment : FenixDialogFragment() { @VisibleForTesting internal fun provideTabId(): String = args.sessionId - @VisibleForTesting - internal fun observeTrackersChange(store: BrowserStore) { - consumeFlow(store) { flow -> - flow.mapNotNull { state -> - state.findTabOrCustomTab(provideTabId()) - }.ifAnyChanged { tab -> - arrayOf( - tab.trackingProtection.blockedTrackers, - tab.trackingProtection.loadedTrackers, - ) - }.collect { - updateTrackers(it) - } - } - } - - @VisibleForTesting - internal fun updateTrackers(tab: SessionState) { - provideTrackingProtectionUseCases().fetchTrackingLogs( - tab.id, - onSuccess = { trackers -> - protectionsView.updateDetailsSection(trackers.isNotEmpty()) - }, - onError = { - Logger.error("QuickSettingsSheetDialogFragment - fetchTrackingLogs onError", it) - }, - ) - } +// Removed as part of Bug_42115: Enhanced Tracking Protection can still be enabled +// @VisibleForTesting +// internal fun observeTrackersChange(store: BrowserStore) { +// consumeFlow(store) { flow -> +// flow.mapNotNull { state -> +// state.findTabOrCustomTab(provideTabId()) +// }.ifAnyChanged { tab -> +// arrayOf( +// tab.trackingProtection.blockedTrackers, +// tab.trackingProtection.loadedTrackers, +// ) +// }.collect { +// updateTrackers(it) +// } +// } +// } + +// Removed as part of Bug_42115: Enhanced Tracking Protection can still be enabled +// @VisibleForTesting +// internal fun updateTrackers(tab: SessionState) { +// provideTrackingProtectionUseCases().fetchTrackingLogs( +// tab.id, +// onSuccess = { trackers -> +// protectionsView.updateDetailsSection(trackers.isNotEmpty()) +// }, +// onError = { +// Logger.error("QuickSettingsSheetDialogFragment - fetchTrackingLogs onError", it) +// }, +// ) +// } @VisibleForTesting internal fun provideTrackingProtectionUseCases() = requireComponents.useCases.trackingProtectionUseCases diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/quicksettings/protections/ProtectionsView.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/quicksettings/protections/ProtectionsView.kt @@ -33,7 +33,7 @@ import org.mozilla.fenix.R import org.mozilla.fenix.databinding.QuicksettingsProtectionsPanelBinding import org.mozilla.fenix.theme.FirefoxTheme import org.mozilla.fenix.trackingprotection.CookieBannerUIMode -import org.mozilla.fenix.trackingprotection.CookieBannerUIMode.REQUEST_UNSUPPORTED_SITE_SUBMITTED +// import org.mozilla.fenix.trackingprotection.CookieBannerUIMode.REQUEST_UNSUPPORTED_SITE_SUBMITTED import org.mozilla.fenix.trackingprotection.CookieBannerUIMode.SITE_NOT_SUPPORTED import org.mozilla.fenix.trackingprotection.ProtectionsState import org.mozilla.fenix.utils.Settings @@ -60,39 +60,45 @@ class ProtectionsView( * Allows changing what this View displays. */ fun update(state: ProtectionsState) { - bindTrackingProtectionInfo(state.isTrackingProtectionEnabled) +// Removed as part of tor-browser#42115: Enhanced Tracking Protection can still be enabled +// bindTrackingProtectionInfo(state.isTrackingProtectionEnabled) bindCookieBannerProtection(state.cookieBannerUIMode) - binding.trackingProtectionSwitch.isVisible = settings.shouldUseTrackingProtection +// Removed as part of tor-browser#42115: Enhanced Tracking Protection can still be enabled +// binding.trackingProtectionSwitch.isVisible = settings.shouldUseTrackingProtection val isPrivateSession = state.tab?.content?.private == true binding.cookieBannerItem.isVisible = isPrivateSession && shouldShowCookieBanner && state.cookieBannerUIMode != CookieBannerUIMode.HIDE - binding.trackingProtectionDetails.setOnClickListener { - interactor.onTrackingProtectionDetailsClicked() - } - updateDividerVisibility() - } - - private fun updateDividerVisibility() { - trackingProtectionDivider.isVisible = !( - !binding.trackingProtectionSwitch.isVisible && - !binding.trackingProtectionDetails.isVisible && - !binding.cookieBannerItem.isVisible - ) - } - - @VisibleForTesting - internal fun updateDetailsSection(show: Boolean) { - binding.trackingProtectionDetails.isVisible = show - updateDividerVisibility() +// Removed as part of tor-browser#42115: Enhanced Tracking Protection can still be enabled +// binding.trackingProtectionDetails.setOnClickListener { +// interactor.onTrackingProtectionDetailsClicked() +// } +// updateDividerVisibility() } - private fun bindTrackingProtectionInfo(isTrackingProtectionEnabled: Boolean) { - binding.trackingProtectionSwitch.isChecked = isTrackingProtectionEnabled - binding.trackingProtectionSwitch.setOnCheckedChangeListener { _, isChecked -> - interactor.onTrackingProtectionToggled(isChecked) - } - } +// Removed as part of tor-browser#42115: Enhanced Tracking Protection can still be enabled +// private fun updateDividerVisibility() { +// trackingProtectionDivider.isVisible = !( +// !binding.trackingProtectionSwitch.isVisible && +// !binding.trackingProtectionDetails.isVisible && +// !binding.cookieBannerItem.isVisible +// ) +// } + +// Removed as part of tor-browser#42115: Enhanced Tracking Protection can still be enabled +// @VisibleForTesting +// internal fun updateDetailsSection(show: Boolean) { +// binding.trackingProtectionDetails.isVisible = show +// updateDividerVisibility() +// } + +// Removed as part of tor-browser#42115: Enhanced Tracking Protection can still be enabled +// private fun bindTrackingProtectionInfo(isTrackingProtectionEnabled: Boolean) { +// binding.trackingProtectionSwitch.isChecked = isTrackingProtectionEnabled +// binding.trackingProtectionSwitch.setOnCheckedChangeListener { _, isChecked -> +// interactor.onTrackingProtectionToggled(isChecked) +// } +// } @VisibleForTesting internal val binding = QuicksettingsProtectionsPanelBinding.inflate( @@ -112,7 +118,7 @@ class ProtectionsView( setContent { FirefoxTheme { if (cookieBannerMode in listOf( - REQUEST_UNSUPPORTED_SITE_SUBMITTED, +// REQUEST_UNSUPPORTED_SITE_SUBMITTED, SITE_NOT_SUPPORTED, ) ) { diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayBanner.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayBanner.kt @@ -334,6 +334,7 @@ private fun TabPageBanner( unselectedContentColor = inactiveColor, ) +/* Tab( selected = config.selectedPage == Page.SyncedTabs, onClick = { callbacks.onTabPageIndicatorClicked(Page.SyncedTabs) }, @@ -352,6 +353,7 @@ private fun TabPageBanner( selectedContentColor = selectedColor, unselectedContentColor = inactiveColor, ) +*/ } Spacer(modifier = Modifier.weight(1.0f)) diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/TorHomePage.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/TorHomePage.kt @@ -0,0 +1,111 @@ +package org.mozilla.fenix.tor + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.paint +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.painter.BrushPainter +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import mozilla.components.compose.base.annotation.FlexibleWindowLightDarkPreview +import org.mozilla.fenix.R + +@Composable +@FlexibleWindowLightDarkPreview +fun TorHomePage( + toolBarAtTop: Boolean = true, +) { + Column( + modifier = Modifier + .fillMaxSize() + .padding( + top = if (toolBarAtTop) dimensionResource(R.dimen.browser_navbar_height) else 0.dp, + bottom = if (!toolBarAtTop) dimensionResource(R.dimen.browser_navbar_height) else 0.dp, + ) + .paint( + BrushPainter( + Brush.linearGradient( + colors = listOf( + colorResource(R.color.tor_homepage_gradient_start), + colorResource(R.color.tor_homepage_gradient_middle), + colorResource(R.color.tor_homepage_gradient_end), + ), + start = Offset(0f, Float.POSITIVE_INFINITY), + end = Offset(Float.POSITIVE_INFINITY, 0f), + ), + ), + ) + .padding( + start = 19.dp, + end = 19.dp, + ) + .verticalScroll(rememberScrollState()), + ) { + Spacer(modifier = Modifier.size(17.dp)) + Row( + modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically, + ) { + Image( + painter = painterResource(R.drawable.tor_browser_app_icon), + contentDescription = null, + Modifier.size(35.dp), + ) + Spacer(modifier = Modifier.size(6.dp)) + Text( + text = stringResource(R.string.app_name), + style = TextStyle( + fontSize = 20.sp, + color = Color(0xDEFFFFFF), + fontWeight = FontWeight.Bold, + ), + ) + } + Spacer(Modifier.weight(1f)) + Text( + // Moved from the commit 5bb3cc6b93346dabd8d46677fae7f86a8f8a4fc2 + // "[android] Modify UI/UX", and the file HomeFragment. + // Splits by full stops or commas and puts the parts in different lines. + // Ignoring separators at the end of the string, it is expected + // that there are at most two parts (e.g. "Explore. Privately."). + text = stringResource(R.string.tor_explore_privately).replace( + " *([.,。।]) *".toRegex(), + "$1\n", + ).trim(), + style = TextStyle( + color = Color(color = 0xDEFFFFFF), + fontSize = 40.sp, + textAlign = TextAlign.Start, + ), + modifier = Modifier.align(Alignment.CenterHorizontally), + ) + Spacer(Modifier.weight(1f)) + Image( + painter = painterResource( + id = R.drawable.ic_onion_pattern, + ), + contentDescription = null, Modifier.fillMaxWidth(), + ) + } + Spacer(modifier = Modifier.size(17.dp)) +} 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 @@ -1499,7 +1499,7 @@ class Settings( val shouldShowSearchSuggestions by booleanPreference( appContext.getPreferenceKey(R.string.pref_key_show_search_suggestions), - default = true, + default = false, ) val shouldAutocompleteInAwesomebar by booleanPreference( @@ -1514,7 +1514,7 @@ class Settings( var shouldShowSearchSuggestionsInPrivate by booleanPreference( appContext.getPreferenceKey(R.string.pref_key_show_search_suggestions_in_private), - default = false, + default = shouldDisableNormalMode, ) /** diff --git a/mobile/android/fenix/app/src/main/res/drawable/ic_favorite.xml b/mobile/android/fenix/app/src/main/res/drawable/ic_favorite.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="18dp" + android:height="18dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,21.35l-1.45,-1.32C5.4,15.36 2,12.28 2,8.5 2,5.42 4.42,3 7.5,3c1.74,0 3.41,0.81 4.5,2.09C13.09,3.81 14.76,3 16.5,3 19.58,3 22,5.42 22,8.5c0,3.78 -3.4,6.86 -8.55,11.54L12,21.35z" + android:fillColor="#ffffff"/> +</vector> diff --git a/mobile/android/fenix/app/src/main/res/drawable/ic_onion_pattern.xml b/mobile/android/fenix/app/src/main/res/drawable/ic_onion_pattern.xml @@ -0,0 +1,806 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="778dp" + android:height="243dp" + android:viewportWidth="778" + android:viewportHeight="243"> + <path + android:pathData="M122.853,121m-39,0a39,39 0,1 1,78 0a39,39 0,1 1,-78 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M122.353,120.5m-29.5,0a29.5,29.5 0,1 1,59 0a29.5,29.5 0,1 1,-59 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M122.353,120.5m-20.5,0a20.5,20.5 0,1 1,41 0a20.5,20.5 0,1 1,-41 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M122.353,120.5m-11.5,0a11.5,11.5 0,1 1,23 0a11.5,11.5 0,1 1,-23 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M250.853,202m-39,0a39,39 0,1 1,78 0a39,39 0,1 1,-78 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M250.353,201.5m-29.5,0a29.5,29.5 0,1 1,59 0a29.5,29.5 0,1 1,-59 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M251.353,202.5m-20.5,0a20.5,20.5 0,1 1,41 0a20.5,20.5 0,1 1,-41 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M250.353,201.5m-11.5,0a11.5,11.5 0,1 1,23 0a11.5,11.5 0,1 1,-23 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M325.853,41m-39,0a39,39 0,1 1,78 0a39,39 0,1 1,-78 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M325.353,41.5m-29.5,0a29.5,29.5 0,1 1,59 0a29.5,29.5 0,1 1,-59 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M325.353,41.5m-20.5,0a20.5,20.5 0,1 1,41 0a20.5,20.5 0,1 1,-41 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M325.353,41.5m-11.5,0a11.5,11.5 0,1 1,23 0a11.5,11.5 0,1 1,-23 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M579.853,202m-39,0a39,39 0,1 1,78 0a39,39 0,1 1,-78 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M579.353,201.5m-29.5,0a29.5,29.5 0,1 1,59 0a29.5,29.5 0,1 1,-59 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M580.353,202.5m-20.5,0a20.5,20.5 0,1 1,41 0a20.5,20.5 0,1 1,-41 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M579.353,201.5m-11.5,0a11.5,11.5 0,1 1,23 0a11.5,11.5 0,1 1,-23 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M653.853,41m-39,0a39,39 0,1 1,78 0a39,39 0,1 1,-78 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M653.353,41.5m-29.5,0a29.5,29.5 0,1 1,59 0a29.5,29.5 0,1 1,-59 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M654.353,41.5m-20.5,0a20.5,20.5 0,1 1,41 0a20.5,20.5 0,1 1,-41 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M653.353,41.5m-11.5,0a11.5,11.5 0,1 1,23 0a11.5,11.5 0,1 1,-23 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M452.853,121m-39,0a39,39 0,1 1,78 0a39,39 0,1 1,-78 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M453.353,120.5m-29.5,0a29.5,29.5 0,1 1,59 0a29.5,29.5 0,1 1,-59 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M453.353,120.5m-20.5,0a20.5,20.5 0,1 1,41 0a20.5,20.5 0,1 1,-41 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M453.353,120.5m-11.5,0a11.5,11.5 0,1 1,23 0a11.5,11.5 0,1 1,-23 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M415.853,202m-39,0a39,39 0,1 1,78 0a39,39 0,1 1,-78 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M415.353,201.5m-29.5,0a29.5,29.5 0,1 1,59 0a29.5,29.5 0,1 1,-59 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M415.353,202.5m-20.5,0a20.5,20.5 0,1 1,41 0a20.5,20.5 0,1 1,-41 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M415.353,201.5m-11.5,0a11.5,11.5 0,1 1,23 0a11.5,11.5 0,1 1,-23 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M489.853,41m-39,0a39,39 0,1 1,78 0a39,39 0,1 1,-78 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M490.353,41.5m-29.5,0a29.5,29.5 0,1 1,59 0a29.5,29.5 0,1 1,-59 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M490.353,41.5m-20.5,0a20.5,20.5 0,1 1,41 0a20.5,20.5 0,1 1,-41 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M490.353,41.5m-11.5,0a11.5,11.5 0,1 1,23 0a11.5,11.5 0,1 1,-23 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M618.853,121m-39,0a39,39 0,1 1,78 0a39,39 0,1 1,-78 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M618.353,120.5m-29.5,0a29.5,29.5 0,1 1,59 0a29.5,29.5 0,1 1,-59 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M618.353,120.5m-20.5,0a20.5,20.5 0,1 1,41 0a20.5,20.5 0,1 1,-41 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M618.353,120.5m-11.5,0a11.5,11.5 0,1 1,23 0a11.5,11.5 0,1 1,-23 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M86.853,202m-39,0a39,39 0,1 1,78 0a39,39 0,1 1,-78 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M86.353,201.5m-29.5,0a29.5,29.5 0,1 1,59 0a29.5,29.5 0,1 1,-59 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M87.353,202.5m-20.5,0a20.5,20.5 0,1 1,41 0a20.5,20.5 0,1 1,-41 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M86.353,201.5m-11.5,0a11.5,11.5 0,1 1,23 0a11.5,11.5 0,1 1,-23 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M159.853,41m-39,0a39,39 0,1 1,78 0a39,39 0,1 1,-78 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M159.353,41.5m-29.5,0a29.5,29.5 0,1 1,59 0a29.5,29.5 0,1 1,-59 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M160.353,41.5m-20.5,0a20.5,20.5 0,1 1,41 0a20.5,20.5 0,1 1,-41 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M159.353,41.5m-11.5,0a11.5,11.5 0,1 1,23 0a11.5,11.5 0,1 1,-23 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M286.853,121m-39,0a39,39 0,1 1,78 0a39,39 0,1 1,-78 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M287.353,120.5m-29.5,0a29.5,29.5 0,1 1,59 0a29.5,29.5 0,1 1,-59 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M287.353,120.5m-20.5,0a20.5,20.5 0,1 1,41 0a20.5,20.5 0,1 1,-41 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M287.353,120.5m-11.5,0a11.5,11.5 0,1 1,23 0a11.5,11.5 0,1 1,-23 0" + android:strokeAlpha="0.1" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M332.853,241C354.392,241 371.853,223.539 371.853,202C371.853,180.461 354.392,163 332.853,163C311.314,163 293.853,180.461 293.853,202C293.853,223.539 311.314,241 332.853,241Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M333.353,231C349.645,231 362.853,217.792 362.853,201.5C362.853,185.208 349.645,172 333.353,172C317.061,172 303.853,185.208 303.853,201.5C303.853,217.792 317.061,231 333.353,231Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M333.353,223C344.675,223 353.853,213.822 353.853,202.5C353.853,191.178 344.675,182 333.353,182C322.031,182 312.853,191.178 312.853,202.5C312.853,213.822 322.031,223 333.353,223Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M333.353,213C339.704,213 344.853,207.851 344.853,201.5C344.853,195.149 339.704,190 333.353,190C327.002,190 321.853,195.149 321.853,201.5C321.853,207.851 327.002,213 333.353,213Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M407.853,80C429.392,80 446.853,62.539 446.853,41C446.853,19.461 429.392,2 407.853,2C386.314,2 368.853,19.461 368.853,41C368.853,62.539 386.314,80 407.853,80Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M407.353,71C423.645,71 436.853,57.792 436.853,41.5C436.853,25.208 423.645,12 407.353,12C391.061,12 377.853,25.208 377.853,41.5C377.853,57.792 391.061,71 407.353,71Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M408.353,62C419.675,62 428.853,52.822 428.853,41.5C428.853,30.178 419.675,21 408.353,21C397.031,21 387.853,30.178 387.853,41.5C387.853,52.822 397.031,62 408.353,62Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M407.353,53C413.704,53 418.853,47.851 418.853,41.5C418.853,35.149 413.704,30 407.353,30C401.002,30 395.853,35.149 395.853,41.5C395.853,47.851 401.002,53 407.353,53Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M74.853,81C96.392,81 113.853,63.539 113.853,42C113.853,20.461 96.392,3 74.853,3C53.314,3 35.853,20.461 35.853,42C35.853,63.539 53.314,81 74.853,81Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M74.353,71C90.645,71 103.853,57.792 103.853,41.5C103.853,25.208 90.645,12 74.353,12C58.061,12 44.853,25.208 44.853,41.5C44.853,57.792 58.061,71 74.353,71Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M75.353,63C86.675,63 95.853,53.822 95.853,42.5C95.853,31.178 86.675,22 75.353,22C64.031,22 54.853,31.178 54.853,42.5C54.853,53.822 64.031,63 75.353,63Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M74.353,53C80.704,53 85.853,47.851 85.853,41.5C85.853,35.149 80.704,30 74.353,30C68.002,30 62.853,35.149 62.853,41.5C62.853,47.851 68.002,53 74.353,53Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M661.853,241C683.392,241 700.853,223.539 700.853,202C700.853,180.461 683.392,163 661.853,163C640.314,163 622.853,180.461 622.853,202C622.853,223.539 640.314,241 661.853,241Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M662.353,231C678.645,231 691.853,217.792 691.853,201.5C691.853,185.208 678.645,172 662.353,172C646.061,172 632.853,185.208 632.853,201.5C632.853,217.792 646.061,231 662.353,231Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M662.353,223C673.675,223 682.853,213.822 682.853,202.5C682.853,191.178 673.675,182 662.353,182C651.031,182 641.853,191.178 641.853,202.5C641.853,213.822 651.031,223 662.353,223Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M662.353,213C668.704,213 673.853,207.851 673.853,201.5C673.853,195.149 668.704,190 662.353,190C656.002,190 650.853,195.149 650.853,201.5C650.853,207.851 656.002,213 662.353,213Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M736.853,80C758.392,80 775.853,62.539 775.853,41C775.853,19.461 758.392,2 736.853,2C715.314,2 697.853,19.461 697.853,41C697.853,62.539 715.314,80 736.853,80Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M736.353,71C752.645,71 765.853,57.792 765.853,41.5C765.853,25.208 752.645,12 736.353,12C720.061,12 706.853,25.208 706.853,41.5C706.853,57.792 720.061,71 736.353,71Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M737.353,62C748.675,62 757.853,52.822 757.853,41.5C757.853,30.178 748.675,21 737.353,21C726.031,21 716.853,30.178 716.853,41.5C716.853,52.822 726.031,62 737.353,62Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M736.353,53C742.704,53 747.853,47.851 747.853,41.5C747.853,35.149 742.704,30 736.353,30C730.002,30 724.853,35.149 724.853,41.5C724.853,47.851 730.002,53 736.353,53Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M496.853,241C518.392,241 535.853,223.539 535.853,202C535.853,180.461 518.392,163 496.853,163C475.314,163 457.853,180.461 457.853,202C457.853,223.539 475.314,241 496.853,241Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M497.353,231C513.645,231 526.853,217.792 526.853,201.5C526.853,185.208 513.645,172 497.353,172C481.061,172 467.853,185.208 467.853,201.5C467.853,217.792 481.061,231 497.353,231Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M497.353,223C508.675,223 517.853,213.822 517.853,202.5C517.853,191.178 508.675,182 497.353,182C486.031,182 476.853,191.178 476.853,202.5C476.853,213.822 486.031,223 497.353,223Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M497.353,213C503.704,213 508.853,207.851 508.853,201.5C508.853,195.149 503.704,190 497.353,190C491.002,190 485.853,195.149 485.853,201.5C485.853,207.851 491.002,213 497.353,213Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M571.853,80C593.392,80 610.853,62.539 610.853,41C610.853,19.461 593.392,2 571.853,2C550.314,2 532.853,19.461 532.853,41C532.853,62.539 550.314,80 571.853,80Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M572.353,71C588.645,71 601.853,57.792 601.853,41.5C601.853,25.208 588.645,12 572.353,12C556.061,12 542.853,25.208 542.853,41.5C542.853,57.792 556.061,71 572.353,71Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M572.353,62C583.675,62 592.853,52.822 592.853,41.5C592.853,30.178 583.675,21 572.353,21C561.031,21 551.853,30.178 551.853,41.5C551.853,52.822 561.031,62 572.353,62Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M572.353,53C578.704,53 583.853,47.851 583.853,41.5C583.853,35.149 578.704,30 572.353,30C566.002,30 560.853,35.149 560.853,41.5C560.853,47.851 566.002,53 572.353,53Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M204.853,160C226.392,160 243.853,142.539 243.853,121C243.853,99.461 226.392,82 204.853,82C183.314,82 165.853,99.461 165.853,121C165.853,142.539 183.314,160 204.853,160Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M204.353,150C220.645,150 233.853,136.792 233.853,120.5C233.853,104.208 220.645,91 204.353,91C188.061,91 174.853,104.208 174.853,120.5C174.853,136.792 188.061,150 204.353,150Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M205.353,141C216.675,141 225.853,131.822 225.853,120.5C225.853,109.178 216.675,100 205.353,100C194.031,100 184.853,109.178 184.853,120.5C184.853,131.822 194.031,141 205.353,141Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M204.353,132C210.704,132 215.853,126.851 215.853,120.5C215.853,114.149 210.704,109 204.353,109C198.002,109 192.853,114.149 192.853,120.5C192.853,126.851 198.002,132 204.353,132Z" + android:strokeAlpha="0.1" + android:strokeLineJoin="round" + android:strokeWidth="4" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1" + android:strokeLineCap="round"/> + <path + android:pathData="M740.853,81C740.853,103.091 723.168,121 701.353,121C679.538,121 661.853,103.091 661.853,81L661.853,81Z" + android:strokeAlpha="0.1" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillAlpha="0.020000001" + android:fillType="evenOdd" + android:strokeColor="#00000000"/> + <path + android:pathData="M740.853,121C740.853,143.091 723.168,161 701.353,161C679.538,161 661.853,143.091 661.853,121L661.853,121Z" + android:strokeAlpha="0.1" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M207.853,162C207.853,184.091 190.168,202 168.353,202C146.538,202 128.853,184.091 128.853,162L128.853,162Z" + android:strokeAlpha="0.1" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillAlpha="0.020000001" + android:fillType="evenOdd" + android:strokeColor="#00000000"/> + <path + android:pathData="M207.853,202C207.853,224.091 190.168,242 168.353,242C146.538,242 128.853,224.091 128.853,202L128.853,202Z" + android:strokeAlpha="0.1" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M281.853,2C281.853,24.091 264.168,42 242.353,42C220.538,42 202.853,24.091 202.853,2L202.853,2Z" + android:strokeAlpha="0.1" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M281.853,43C281.853,65.091 264.168,83 242.353,83C220.538,83 202.853,65.091 202.853,43L202.853,43Z" + android:strokeAlpha="0.1" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillAlpha="0.020000001" + android:fillType="evenOdd" + android:strokeColor="#00000000"/> + <path + android:pathData="M575.853,117C575.853,94.909 558.168,77 536.353,77C514.538,77 496.853,94.909 496.853,117L496.853,117Z" + android:strokeAlpha="0.1" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M575.853,158C575.853,135.909 558.168,118 536.353,118C514.538,118 496.853,135.909 496.853,158L496.853,158Z" + android:strokeAlpha="0.1" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillAlpha="0.020000001" + android:fillType="evenOdd" + android:strokeColor="#00000000"/> + <path + android:pathData="M79.853,121C79.853,98.909 62.168,81 40.353,81C18.538,81 0.853,98.909 0.853,121L0.853,121Z" + android:strokeAlpha="0.1" + android:strokeWidth="1" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M79.853,161C79.853,138.909 62.168,121 40.353,121C18.538,121 0.853,138.909 0.853,161L0.853,161Z" + android:strokeAlpha="0.1" + android:strokeWidth="1" + android:fillColor="#00000000" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> + <path + android:pathData="M329.353,81.5C351.444,81.5 369.353,99.185 369.353,121C369.353,142.815 351.444,160.5 329.353,160.5L329.353,160.5Z" + android:strokeAlpha="0.1" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:fillAlpha="0.020000001" + android:fillType="evenOdd" + android:strokeColor="#00000000"/> + <path + android:pathData="M370.353,81.5C392.444,81.5 410.353,99.185 410.353,121C410.353,142.815 392.444,160.5 370.353,160.5L370.353,160.5Z" + android:strokeAlpha="0.1" + android:strokeWidth="1" + android:fillColor="#FFFFFF" + android:strokeColor="#FFFFFF" + android:fillType="evenOdd" + android:fillAlpha="0.1"/> +</vector> diff --git a/mobile/android/fenix/app/src/main/res/drawable/ic_screenshot.xml b/mobile/android/fenix/app/src/main/res/drawable/ic_screenshot.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="18dp" + android:height="18dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M3,4V1h2v3h3v2H5v3H3V6H0V4H3zM6,10V7h3V4h7l1.83,2H21c1.1,0 2,0.9 2,2v12c0,1.1 -0.9,2 -2,2H5c-1.1,0 -2,-0.9 -2,-2V10H6zM13,19c2.76,0 5,-2.24 5,-5s-2.24,-5 -5,-5s-5,2.24 -5,5S10.24,19 13,19zM9.8,14c0,1.77 1.43,3.2 3.2,3.2s3.2,-1.43 3.2,-3.2s-1.43,-3.2 -3.2,-3.2S9.8,12.23 9.8,14z" + android:fillColor="#ffffff"/> +</vector> diff --git a/mobile/android/fenix/app/src/main/res/drawable/rounded_corners.xml b/mobile/android/fenix/app/src/main/res/drawable/rounded_corners.xml @@ -0,0 +1,11 @@ +<?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/. --> + +<!-- Used for rounding the corners of a button --> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="#03DAC5" /> + <corners android:radius="4dp" /> +</shape> diff --git a/mobile/android/fenix/app/src/main/res/drawable/tor_bootstrap_background_gradient.xml b/mobile/android/fenix/app/src/main/res/drawable/tor_bootstrap_background_gradient.xml @@ -0,0 +1,16 @@ +<?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/. --> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item> + <shape> + <gradient + android:angle="225" + android:startColor="#FF7329A4" + android:centerColor="#FF3A3274" + android:endColor="#FF3A3274" + android:type="linear" /> + </shape> + </item> +</selector> diff --git a/mobile/android/fenix/app/src/main/res/drawable/tor_onboarding_donate_gradient.xml b/mobile/android/fenix/app/src/main/res/drawable/tor_onboarding_donate_gradient.xml @@ -0,0 +1,15 @@ +<?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/. --> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item> + <shape> + <gradient + android:angle="45" + android:startColor="#07d1db" + android:endColor="#b240f5" + android:type="linear" /> + </shape> + </item> +</selector> diff --git a/mobile/android/fenix/app/src/main/res/drawable/tor_onboarding_donate_rounded_corners.xml b/mobile/android/fenix/app/src/main/res/drawable/tor_onboarding_donate_rounded_corners.xml @@ -0,0 +1,11 @@ +<?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/. --> + +<!-- Used for rounding the corners of a button --> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="#70efde" /> + <corners android:radius="10dp" /> +</shape> diff --git a/mobile/android/fenix/app/src/main/res/layout/fragment_home.xml b/mobile/android/fenix/app/src/main/res/layout/fragment_home.xml @@ -33,41 +33,6 @@ android:layout_width="match_parent" android:layout_height="match_parent" app:layout_scrollFlags="scroll"> - - <LinearLayout - android:id="@+id/wordmark" - android:layout_width="wrap_content" - android:layout_height="40dp" - android:layout_marginStart="16dp" - android:layout_marginTop="18dp" - android:layout_marginBottom="32dp" - android:clickable="false" - android:focusable="false" - android:orientation="horizontal" - app:layout_collapseMode="parallax" - android:contentDescription="@string/app_name" - app:layout_collapseParallaxMultiplier=".1"> - - <ImageView - android:id="@+id/wordmarkLogo" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:layout_marginEnd="10.dp" - android:adjustViewBounds="true" - app:srcCompat="?fenixWordmarkLogo" - android:contentDescription="@null" - tools:ignore="ImageContrastCheck" /> - - <ImageView - android:id="@+id/wordmarkText" - android:layout_width="wrap_content" - android:layout_height="@dimen/wordmark_text_height" - android:adjustViewBounds="true" - android:contentDescription="@null" - android:layout_marginTop="@dimen/wordmark_text_margin_top" - app:srcCompat="?fenixWordmarkText" /> - </LinearLayout> - </com.google.android.material.appbar.CollapsingToolbarLayout> </com.google.android.material.appbar.AppBarLayout> @@ -78,6 +43,11 @@ android:layout_height="match_parent" app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" /> + <androidx.compose.ui.platform.ComposeView + android:id="@+id/torHomepageView" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + <ViewStub android:id="@+id/toolbarLayoutStub" android:layout_width="match_parent" diff --git a/mobile/android/fenix/app/src/main/res/layout/quicksettings_permissions.xml b/mobile/android/fenix/app/src/main/res/layout/quicksettings_permissions.xml @@ -180,7 +180,7 @@ app:layout_constraintEnd_toStartOf="@id/mediaKeySystemAccessStatus" app:layout_constraintStart_toStartOf="parent" android:textColor="?attr/textPrimary" - tools:visibility="visible" /> + tools:visibility="gone" /> <TextView android:id="@+id/mediaKeySystemAccessStatus" @@ -192,7 +192,7 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@id/mediaKeySystemAccessLabel" tools:text="@string/preference_option_phone_feature_blocked" - tools:visibility="visible" /> + tools:visibility="gone" /> <TextView android:id="@+id/localDeviceAccessLabel" diff --git a/mobile/android/fenix/app/src/main/res/layout/quicksettings_protections_panel.xml b/mobile/android/fenix/app/src/main/res/layout/quicksettings_protections_panel.xml @@ -12,36 +12,38 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:minHeight="@dimen/tracking_protection_item_height" - app:layout_constraintBottom_toTopOf="@id/trackingProtectionSwitch" + app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toTopOf="parent" /> - <org.mozilla.fenix.trackingprotection.SwitchWithDescription - android:id="@+id/trackingProtectionSwitch" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="16dp" - android:minHeight="@dimen/tracking_protection_item_height" - android:text="@string/preference_enhanced_tracking_protection" - app:layout_constraintBottom_toTopOf="@id/trackingProtectionDetails" - app:layout_constraintTop_toBottomOf="@id/cookieBannerItem" - app:switchDescriptionOff="@string/etp_panel_off" - app:switchDescriptionOn="@string/etp_panel_on" - app:switchIconOff="@drawable/ic_tracking_protection_disabled" - app:switchIconOn="@drawable/ic_tracking_protection_enabled" - app:switchTitle="@string/preference_enhanced_tracking_protection" /> +<!-- Removed as part of Bug_42115: Enhanced Tracking Protection can still be enabled--> +<!-- <org.mozilla.fenix.trackingprotection.SwitchWithDescription--> +<!-- android:id="@+id/trackingProtectionSwitch"--> +<!-- android:layout_width="match_parent"--> +<!-- android:layout_height="wrap_content"--> +<!-- android:layout_marginTop="16dp"--> +<!-- android:minHeight="@dimen/tracking_protection_item_height"--> +<!-- android:text="@string/preference_enhanced_tracking_protection"--> +<!-- app:layout_constraintBottom_toTopOf="@id/trackingProtectionDetails"--> +<!-- app:layout_constraintTop_toBottomOf="@id/cookieBannerItem"--> +<!-- app:switchDescriptionOff="@string/etp_panel_off"--> +<!-- app:switchDescriptionOn="@string/etp_panel_on"--> +<!-- app:switchIconOff="@drawable/ic_tracking_protection_disabled"--> +<!-- app:switchIconOn="@drawable/ic_tracking_protection_enabled"--> +<!-- app:switchTitle="@string/preference_enhanced_tracking_protection" />--> - <TextView - android:id="@+id/trackingProtectionDetails" - style="@style/QuickSettingsText.Icon" - android:layout_width="0dp" - android:layout_height="@dimen/quicksettings_item_height" - android:layout_alignParentEnd="true" - android:gravity="end|center_vertical" - android:text="@string/enhanced_tracking_protection_details" - android:visibility="gone" - app:drawableEndCompat="@drawable/ic_arrowhead_right" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" /> + <!-- Removed as part of Bug_42115: Enhanced Tracking Protection can still be enabled--> +<!-- <TextView--> +<!-- android:id="@+id/trackingProtectionDetails"--> +<!-- style="@style/QuickSettingsText.Icon"--> +<!-- android:layout_width="0dp"--> +<!-- android:layout_height="@dimen/quicksettings_item_height"--> +<!-- android:layout_alignParentEnd="true"--> +<!-- android:gravity="end|center_vertical"--> +<!-- android:text="@string/enhanced_tracking_protection_details"--> +<!-- android:visibility="gone"--> +<!-- app:drawableEndCompat="@drawable/ic_arrowhead_right"--> +<!-- app:layout_constraintBottom_toBottomOf="parent"--> +<!-- app:layout_constraintEnd_toEndOf="parent"--> +<!-- app:layout_constraintStart_toStartOf="parent" />--> </androidx.constraintlayout.widget.ConstraintLayout> diff --git a/mobile/android/fenix/app/src/main/res/layout/search_widget_extra_small_v1.xml b/mobile/android/fenix/app/src/main/res/layout/search_widget_extra_small_v1.xml @@ -18,6 +18,8 @@ android:layout_gravity="center" android:contentDescription="@string/search_widget_content_description_2" android:scaleType="centerInside" - tools:src="@mipmap/ic_launcher_foreground"/> + tools:src="@mipmap/ic_launcher_foreground" + android:scaleX="1.5" + android:scaleY="1.5"/> </FrameLayout> diff --git a/mobile/android/fenix/app/src/main/res/layout/search_widget_extra_small_v2.xml b/mobile/android/fenix/app/src/main/res/layout/search_widget_extra_small_v2.xml @@ -18,5 +18,7 @@ android:layout_gravity="center" android:contentDescription="@string/search_widget_content_description_2" android:scaleType="centerInside" - tools:src="@mipmap/ic_launcher_foreground"/> + tools:src="@mipmap/ic_launcher_foreground" + android:scaleX="1.5" + android:scaleY="1.5"/> </FrameLayout> diff --git a/mobile/android/fenix/app/src/main/res/layout/search_widget_large.xml b/mobile/android/fenix/app/src/main/res/layout/search_widget_large.xml @@ -17,6 +17,8 @@ android:padding="12dp" android:layout_alignParentStart="true" android:contentDescription="@string/search_widget_content_description_2" + android:scaleX="1.5" + android:scaleY="1.5" android:scaleType="centerInside" /> <TextView diff --git a/mobile/android/fenix/app/src/main/res/layout/search_widget_medium.xml b/mobile/android/fenix/app/src/main/res/layout/search_widget_medium.xml @@ -17,6 +17,8 @@ android:layout_height="50dp" android:padding="12dp" android:layout_alignParentStart="true" + android:scaleX="1.5" + android:scaleY="1.5" android:scaleType="centerInside" /> <TextView diff --git a/mobile/android/fenix/app/src/main/res/layout/search_widget_small.xml b/mobile/android/fenix/app/src/main/res/layout/search_widget_small.xml @@ -15,6 +15,8 @@ android:layout_height="50dp" android:padding="12dp" android:contentDescription="@string/search_widget_content_description_2" + android:scaleX="1.5" + android:scaleY="1.5" android:scaleType="centerInside" /> <ImageView diff --git a/mobile/android/fenix/app/src/main/res/navigation/nav_graph.xml b/mobile/android/fenix/app/src/main/res/navigation/nav_graph.xml @@ -209,6 +209,9 @@ <action android:id="@+id/action_global_to_installedAddonDetailsFragment" app:destination="@id/installedAddonDetailsFragment" /> + <action + android:id="@+id/action_global_homeFragment" + app:destination="@id/homeFragment" /> <dialog android:id="@+id/tabsTrayFragment" @@ -1028,6 +1031,11 @@ app:nullable="true" /> </fragment> <fragment + android:id="@+id/torBridgeConfigFragment" + android:name="org.mozilla.fenix.settings.TorBridgeConfigFragment" + android:label="@string/preferences_tor_network_settings_bridge_config" + tools:layout="@layout/fragment_tor_bridge_config" /> + <fragment android:id="@+id/trackingProtectionFragment" android:name="org.mozilla.fenix.settings.TrackingProtectionFragment"> <argument diff --git a/mobile/android/fenix/app/src/main/res/values/attrs.xml b/mobile/android/fenix/app/src/main/res/values/attrs.xml @@ -52,6 +52,7 @@ <attr name="menuItemButtonTintColor" format="reference"/> <!-- Misc --> + <attr name="torBootstrapBackground" format="reference"/> <attr name="bottomBarBackground" format="reference"/> <attr name="bottomBarBackgroundTop" format="reference"/> <attr name="fenixLogo" format="reference" /> diff --git a/mobile/android/fenix/app/src/main/res/values/colors.xml b/mobile/android/fenix/app/src/main/res/values/colors.xml @@ -297,6 +297,11 @@ <!-- Private Mode mask icon circle fill colors --> <color name="mozac_ui_private_mode_circle_fill" tools:ignore="UnusedResources">@color/photonPurple60</color> + + <!-- TorHomepage gradient colors --> + <color name="tor_homepage_gradient_start">#7529A7</color> + <color name="tor_homepage_gradient_middle">#492E85</color> + <color name="tor_homepage_gradient_end">#383372</color> <!-- Account Sync Avatar fill colors --> <color name="mozac_ui_avatar_warning_bg_fill_critical" tools:ignore="UnusedResources">@color/fx_mobile_icon_color_secondary</color> diff --git a/mobile/android/fenix/app/src/main/res/values/preference_keys.xml b/mobile/android/fenix/app/src/main/res/values/preference_keys.xml @@ -45,6 +45,7 @@ <string name="pref_key_override_amo_collection" translatable="false">pref_key_override_amo_collection</string> <string name="pref_key_enable_gecko_logs" translatable="false">pref_key_enable_gecko_logs</string> <string name="pref_key_rate" translatable="false">pref_key_rate</string> + <string name="pref_key_donate" translatable="false">pref_key_donate</string> <string name="pref_key_about" translatable="false">pref_key_about</string> <string name="pref_key_account" translatable="false">pref_key_account</string> <string name="pref_key_sign_in" translatable="false">pref_key_sign_in</string> diff --git a/mobile/android/fenix/app/src/main/res/values/styles.xml b/mobile/android/fenix/app/src/main/res/values/styles.xml @@ -548,10 +548,18 @@ <item name="android:fontWeight">@integer/font_weight_medium</item> </style> + <style name="TorHeaderTextStyle" parent="TextAppearance.MaterialComponents.Subtitle1"> + <item name="android:textSize">18sp</item> + <item name="android:textColor">#000000</item> + <item name="android:textFontWeight" tools:ignore="NewApi">@integer/font_weight_medium</item> + <item name="android:fontWeight" tools:ignore="NewApi">@integer/font_weight_medium</item> + </style> + <style name="Header24TextStyle" parent="TextAppearance.MaterialComponents.Body1"> <item name="android:textColor">?textPrimary</item> <item name="android:textSize">24sp</item> - <item name="fontFamily">@font/metropolis_semibold</item> + <item name="android:textFontWeight" tools:ignore="NewApi">@integer/font_weight_medium</item> + <item name="android:fontWeight" tools:ignore="NewApi">@integer/font_weight_medium</item> </style> <style name="Header20TextStyle" parent="TextAppearance.MaterialComponents.Body1" tools:ignore="UnusedResources"> @@ -595,6 +603,10 @@ <item name="android:textAllCaps">false</item> </style> + <style name="TorBody16TextStyle" parent="TextAppearance.MaterialComponents.Body1"> + <item name="android:textColor">#000000</item> + </style> + <style name="Subtitle12TextStyle" parent="TextAppearance.MaterialComponents.Body1"> <item name="android:textColor">?attr/textSecondary</item> <item name="android:textSize">12sp</item> diff --git a/mobile/android/fenix/app/src/main/res/xml/logins_preferences.xml b/mobile/android/fenix/app/src/main/res/xml/logins_preferences.xml @@ -18,6 +18,7 @@ android:title="@string/preferences_android_autofill" android:summary="@string/preferences_android_autofill_description" /> <org.mozilla.fenix.settings.SyncPreference + app:isPreferenceVisible="false" android:key="@string/pref_key_sync_logins" android:title="@string/preferences_passwords_sync_logins_2" /> <Preference diff --git a/mobile/android/fenix/app/src/main/res/xml/preferences.xml b/mobile/android/fenix/app/src/main/res/xml/preferences.xml @@ -11,6 +11,7 @@ android:layout="@layout/sign_in_preference" android:summary="@string/preferences_sign_in_description" android:title="@string/preferences_sign_in" + app:isPreferenceVisible="false" app:allowDividerBelow="false" /> <androidx.preference.PreferenceCategory @@ -47,10 +48,10 @@ android:key="@string/pref_key_tabs" android:title="@string/preferences_tabs" /> - <androidx.preference.Preference + <!--<androidx.preference.Preference app:iconSpaceReserved="false" android:key="@string/pref_key_home" - android:title="@string/preferences_home_2" /> + android:title="@string/preferences_home_2" />--> <androidx.preference.Preference android:key="@string/pref_key_customize" @@ -64,6 +65,7 @@ <androidx.preference.Preference app:iconSpaceReserved="false" + app:isPreferenceVisible="false" android:key="@string/pref_key_credit_cards" android:title="@string/preferences_credit_cards_2" /> @@ -120,6 +122,7 @@ <androidx.preference.Preference android:key="@string/pref_key_tracking_protection_settings" app:iconSpaceReserved="false" + app:isPreferenceVisible="false" android:title="@string/preference_enhanced_tracking_protection" /> <androidx.preference.Preference @@ -145,6 +148,7 @@ <androidx.preference.Preference android:key="@string/pref_key_data_choices" app:iconSpaceReserved="false" + app:isPreferenceVisible="false" android:title="@string/preferences_data_collection" /> </androidx.preference.PreferenceCategory> @@ -153,6 +157,7 @@ android:title="@string/preferences_category_advanced" android:key="@string/pref_key_advanced" android:layout="@layout/preference_category_no_icon_style"> + <androidx.preference.Preference android:key="@string/pref_key_addons" app:iconSpaceReserved="false" @@ -226,6 +231,11 @@ android:title="@string/preferences_about" /> <androidx.preference.Preference + android:icon="@drawable/ic_favorite" + android:key="@string/pref_key_donate" + android:title="@string/preferences_donate" /> + + <androidx.preference.Preference android:key="@string/pref_key_debug_settings" app:iconSpaceReserved="false" android:title="@string/preferences_debug_settings" diff --git a/mobile/android/fenix/app/src/main/res/xml/site_permissions_details_exceptions_preferences.xml b/mobile/android/fenix/app/src/main/res/xml/site_permissions_details_exceptions_preferences.xml @@ -44,6 +44,7 @@ android:icon="@drawable/ic_link" android:key="@string/pref_key_browser_feature_media_key_system_access" android:title="@string/preference_phone_feature_media_key_system_access" + app:isPreferenceVisible="false" android:summary="@string/preference_option_phone_feature_ask_to_allow"/> <androidx.preference.Preference diff --git a/mobile/android/fenix/app/src/main/res/xml/site_permissions_preferences.xml b/mobile/android/fenix/app/src/main/res/xml/site_permissions_preferences.xml @@ -73,6 +73,7 @@ android:key="@string/pref_key_browser_feature_media_key_system_access" android:title="@string/preference_phone_feature_media_key_system_access" android:summary="@string/preference_option_phone_feature_ask_to_allow" + app:isPreferenceVisible="false" app:allowDividerBelow="true"/> <androidx.preference.Preference diff --git a/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/settings/SupportUtilsTest.kt b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/settings/SupportUtilsTest.kt @@ -33,19 +33,10 @@ class SupportUtilsTest { Locale.forLanguageTag("fr"), ), ) - assertEquals( - "https://support.mozilla.org/1/firefox/20/Android/fr/tracking-protection-firefox-android", - SupportUtils.getSumoURLForTopic( - mockContext("2 0"), - SupportUtils.SumoTopic.TRACKING_PROTECTION, - Locale.forLanguageTag("fr"), - useMobilePage = false, - ), - ) - assertEquals( - "https://www.mozilla.org/firefox/android/notes", - SupportUtils.WHATS_NEW_URL, - ) + // assertEquals( + // "https://www.mozilla.org/firefox/android/notes", + // SupportUtils.WHATS_NEW_URL, + // ) } @Test @@ -72,6 +63,18 @@ class SupportUtilsTest { ) } + @Test + fun getTorPageUrl() { + assertEquals( + "https://tb-manual.torproject.org/mobile-tor", + SupportUtils.getTorHelpPageUrl() + ) + assertEquals( + "https://www.torproject.org/releases/", + SupportUtils.getTorWhatsNewUrl() + ) + } + private fun mockContext(versionName: String): Context { val context: Context = mockk() val packageManager: PackageManager = mockk() diff --git a/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/settings/quicksettings/QuickSettingsSheetDialogFragmentTest.kt b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/settings/quicksettings/QuickSettingsSheetDialogFragmentTest.kt @@ -52,111 +52,111 @@ class QuickSettingsSheetDialogFragmentTest { every { fragment.activity } returns mockk(relaxed = true) } - @Test - fun `WHEN a tracker is loaded THEN trackers view is updated`() { - val tab = createTab("mozilla.org") - - every { fragment.provideTabId() } returns tab.id - every { fragment.updateTrackers(any()) } returns Unit - - fragment.observeTrackersChange(store) - - addAndSelectTab(tab) - - verify(exactly = 1) { - fragment.updateTrackers(tab) - } - - store.dispatch(TrackerLoadedAction(tab.id, mockk())) - - val updatedTab = store.state.findTab(tab.id)!! - - assertNotSame(updatedTab, tab) - - verify(exactly = 1) { - fragment.updateTrackers(updatedTab) - } - } - - @Test - fun `WHEN a tracker is blocked THEN trackers view is updated`() { - val tab = createTab("mozilla.org") - - every { fragment.provideTabId() } returns tab.id - every { fragment.updateTrackers(any()) } returns Unit - - fragment.observeTrackersChange(store) - - addAndSelectTab(tab) - - verify(exactly = 1) { - fragment.updateTrackers(tab) - } - - store.dispatch(TrackerBlockedAction(tab.id, mockk())) - - val updatedTab = store.state.findTab(tab.id)!! - - assertNotSame(updatedTab, tab) - - verify(exactly = 1) { - fragment.updateTrackers(updatedTab) - } - } - - @Test - fun `GIVEN no trackers WHEN calling updateTrackers THEN hide the details section`() { - val tab = createTab("mozilla.org") - val trackingProtectionUseCases: TrackingProtectionUseCases = mockk(relaxed = true) - val protectionsView: ProtectionsView = mockk(relaxed = true) - - val onComplete = slot<(List<TrackerLog>) -> Unit>() - - every { fragment.protectionsView } returns protectionsView - - every { - trackingProtectionUseCases.fetchTrackingLogs.invoke( - any(), - capture(onComplete), - any(), - ) - }.answers { onComplete.captured.invoke(emptyList()) } - - every { fragment.provideTrackingProtectionUseCases() } returns trackingProtectionUseCases - - fragment.updateTrackers(tab) - - verify { - protectionsView.updateDetailsSection(false) - } - } - - @Test - fun `GIVEN trackers WHEN calling updateTrackers THEN show the details section`() { - val tab = createTab("mozilla.org") - val trackingProtectionUseCases: TrackingProtectionUseCases = mockk(relaxed = true) - val protectionsView: ProtectionsView = mockk(relaxed = true) - - val onComplete = slot<(List<TrackerLog>) -> Unit>() - - every { fragment.protectionsView } returns protectionsView - - every { - trackingProtectionUseCases.fetchTrackingLogs.invoke( - any(), - capture(onComplete), - any(), - ) - }.answers { onComplete.captured.invoke(listOf(TrackerLog(""))) } - - every { fragment.provideTrackingProtectionUseCases() } returns trackingProtectionUseCases - - fragment.updateTrackers(tab) - - verify { - protectionsView.updateDetailsSection(true) - } - } +// @Test +// fun `WHEN a tracker is loaded THEN trackers view is updated`() { +// val tab = createTab("mozilla.org") +// +// every { fragment.provideTabId() } returns tab.id +// every { fragment.updateTrackers(any()) } returns Unit +// +// fragment.observeTrackersChange(store) +// +// addAndSelectTab(tab) +// +// verify(exactly = 1) { +// fragment.updateTrackers(tab) +// } +// +// store.dispatch(TrackerLoadedAction(tab.id, mockk())) +// +// val updatedTab = store.state.findTab(tab.id)!! +// +// assertNotSame(updatedTab, tab) +// +// verify(exactly = 1) { +// fragment.updateTrackers(updatedTab) +// } +// } + +// @Test +// fun `WHEN a tracker is blocked THEN trackers view is updated`() { +// val tab = createTab("mozilla.org") +// +// every { fragment.provideTabId() } returns tab.id +// every { fragment.updateTrackers(any()) } returns Unit +// +// fragment.observeTrackersChange(store) +// +// addAndSelectTab(tab) +// +// verify(exactly = 1) { +// fragment.updateTrackers(tab) +// } +// +// store.dispatch(TrackerBlockedAction(tab.id, mockk())) +// +// val updatedTab = store.state.findTab(tab.id)!! +// +// assertNotSame(updatedTab, tab) +// +// verify(exactly = 1) { +// fragment.updateTrackers(updatedTab) +// } +// } + +// @Test +// fun `GIVEN no trackers WHEN calling updateTrackers THEN hide the details section`() { +// val tab = createTab("mozilla.org") +// val trackingProtectionUseCases: TrackingProtectionUseCases = mockk(relaxed = true) +// val protectionsView: ProtectionsView = mockk(relaxed = true) +// +// val onComplete = slot<(List<TrackerLog>) -> Unit>() +// +// every { fragment.protectionsView } returns protectionsView +// +// every { +// trackingProtectionUseCases.fetchTrackingLogs.invoke( +// any(), +// capture(onComplete), +// any(), +// ) +// }.answers { onComplete.captured.invoke(emptyList()) } +// +// every { fragment.provideTrackingProtectionUseCases() } returns trackingProtectionUseCases +// +// fragment.updateTrackers(tab) +// +// verify { +// protectionsView.updateDetailsSection(false) +// } +// } + +// @Test +// fun `GIVEN trackers WHEN calling updateTrackers THEN show the details section`() { +// val tab = createTab("mozilla.org") +// val trackingProtectionUseCases: TrackingProtectionUseCases = mockk(relaxed = true) +// val protectionsView: ProtectionsView = mockk(relaxed = true) +// +// val onComplete = slot<(List<TrackerLog>) -> Unit>() +// +// every { fragment.protectionsView } returns protectionsView +// +// every { +// trackingProtectionUseCases.fetchTrackingLogs.invoke( +// any(), +// capture(onComplete), +// any(), +// ) +// }.answers { onComplete.captured.invoke(listOf(TrackerLog(""))) } +// +// every { fragment.provideTrackingProtectionUseCases() } returns trackingProtectionUseCases +// +// fragment.updateTrackers(tab) +// +// verify { +// protectionsView.updateDetailsSection(true) +// } +// } private fun addAndSelectTab(tab: TabSessionState) { store.dispatch(TabListAction.AddTabAction(tab))