1
0
Fork 0

Copione merged onto master
continuous-integration/drone/push Build is passing Details

master
blallo 2020-06-28 00:01:14 +02:00
commit 2abc9d72d3
74 changed files with 1354 additions and 660 deletions

File diff suppressed because it is too large Load Diff

View File

@ -340,7 +340,7 @@ class BookmarksTest {
}
multipleSelectionToolbar {
}.clickOpenNewTab { }.openTabDrawer {
}.clickOpenNewTab {
verifyNormalModeSelected()
verifyExistingTabList()
}
@ -363,7 +363,7 @@ class BookmarksTest {
}
multipleSelectionToolbar {
}.clickOpenPrivateTab { }.openTabDrawer {
}.clickOpenPrivateTab {
verifyPrivateModeSelected()
verifyExistingTabList()
}

View File

@ -216,7 +216,7 @@ class HistoryTest {
}
multipleSelectionToolbar {
}.clickOpenNewTab { }.openTabDrawer {
}.clickOpenNewTab {
verifyExistingTabList()
verifyNormalModeSelected()
}
@ -236,7 +236,7 @@ class HistoryTest {
}
multipleSelectionToolbar {
}.clickOpenPrivateTab { }.openTabDrawer {
}.clickOpenPrivateTab {
verifyPrivateModeSelected()
verifyExistingTabList()
}

View File

@ -50,6 +50,12 @@ class SearchTest {
@Test
fun shortcutButtonTest() {
homeScreen {
}.openThreeDotMenu {
}.openSettings {
}.openSearchSubMenu {
enableShowSearchShortcuts()
}.goBack {
}.goBack {
}.openSearch {
verifySearchWithText()
clickSearchEngineButton("DuckDuckGo")
@ -63,6 +69,12 @@ class SearchTest {
@Test
fun shortcutSearchEngineSettingsTest() {
homeScreen {
}.openThreeDotMenu {
}.openSettings {
}.openSearchSubMenu {
enableShowSearchShortcuts()
}.goBack {
}.goBack {
}.openSearch {
scrollToSearchEngineSettings()
clickSearchEngineSettings()

View File

@ -85,23 +85,26 @@ class LibrarySubMenusMultipleSelectionToolbarRobot {
return BookmarksRobot.Transition()
}
fun clickOpenNewTab(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition {
fun clickOpenNewTab(interact: TabDrawerRobot.() -> Unit): TabDrawerRobot.Transition {
openInNewTabButton().click()
mDevice.waitNotNull(Until.findObject(By.text("Collections")), waitingTime)
HomeScreenRobot().interact()
return HomeScreenRobot.Transition()
}
fun clickOpenPrivateTab(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition {
openInPrivateTabButton().click()
mDevice.waitNotNull(
Until.findObject(By.text(PRIVATE_SESSION_MESSAGE)),
Until.findObject(By.res("org.mozilla.fenix.debug:id/tab_layout")),
waitingTime
)
HomeScreenRobot().interact()
return HomeScreenRobot.Transition()
TabDrawerRobot().interact()
return TabDrawerRobot.Transition()
}
fun clickOpenPrivateTab(interact: TabDrawerRobot.() -> Unit): TabDrawerRobot.Transition {
openInPrivateTabButton().click()
mDevice.waitNotNull(
Until.findObject(By.res("org.mozilla.fenix.debug:id/tab_layout")),
waitingTime
)
TabDrawerRobot().interact()
return TabDrawerRobot.Transition()
}
}
}

View File

@ -36,6 +36,7 @@ class SettingsSubMenuSearchRobot {
selectDefaultSearchEngine(searchEngineName)
fun disableShowSearchSuggestions() = toggleShowSearchSuggestions()
fun enableShowSearchShortcuts() = toggleShowSearchShortcuts()
class Transition {
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
@ -142,5 +143,16 @@ private fun toggleShowSearchSuggestions() {
.perform(click())
}
private fun toggleShowSearchShortcuts() {
onView(withId(androidx.preference.R.id.recycler_view)).perform(
RecyclerViewActions.scrollTo<RecyclerView.ViewHolder>(
hasDescendant(withText("Show search shortcuts"))
)
)
onView(withText("Show search shortcuts"))
.perform(click())
}
private fun goBackButton() =
onView(CoreMatchers.allOf(withContentDescription("Navigate up")))

View File

@ -26,6 +26,7 @@ import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.By
import androidx.test.uiautomator.By.text
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.Until
import androidx.test.uiautomator.Until.findObject
import org.hamcrest.CoreMatchers.allOf
import org.mozilla.fenix.R
@ -104,6 +105,20 @@ class TabDrawerRobot {
return ThreeDotMenuMainRobot.Transition()
}
fun openTabDrawer(interact: TabDrawerRobot.() -> Unit): TabDrawerRobot.Transition {
org.mozilla.fenix.ui.robots.mDevice.waitForIdle()
tabsCounter().click()
org.mozilla.fenix.ui.robots.mDevice.waitNotNull(
Until.findObject(By.res("org.mozilla.fenix.debug:id/tab_layout")),
waitingTime
)
TabDrawerRobot().interact()
return TabDrawerRobot.Transition()
}
fun openHomeScreen(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition {
mDevice.waitForIdle()
@ -196,3 +211,5 @@ private fun tab(title: String) =
withText(title)
)
)
private fun tabsCounter() = onView(withId(R.id.tab_button))

View File

@ -23,7 +23,7 @@ object FeatureFlags {
/**
* Enable tab sync feature
*/
val syncedTabs = Config.channel.isNightlyOrDebug
const val syncedTabs = true
/**
* Enables new tab tray pref

View File

@ -173,6 +173,9 @@ open class FenixApplication : LocaleAwareApplication() {
taskQueue.runIfReadyOrQueue {
Experiments.initialize(
applicationContext = applicationContext,
onExperimentsUpdated = {
ExperimentsManager.initSearchWidgetExperiment(this)
},
configuration = mozilla.components.service.experiments.Configuration(
httpClient = components.core.client,
kintoEndpoint = KINTO_ENDPOINT_PROD

View File

@ -174,10 +174,14 @@ open class HomeActivity : LocaleAwareAppCompatActivity() {
lifecycle.addObserver(BreadcrumbsRecorder(components.analytics.crashReporter,
navHost.navController, ::getBreadcrumbMessage))
intent
?.toSafeIntent()
val safeIntent = intent?.toSafeIntent()
safeIntent
?.let(::getIntentSource)
?.also { components.analytics.metrics.track(Event.OpenedApp(it)) }
// record on cold startup
safeIntent
?.let(::getIntentAllSource)
?.also { components.analytics.metrics.track(Event.AppRecievedIntent(it)) }
}
supportActionBar?.hide()
@ -250,6 +254,15 @@ open class HomeActivity : LocaleAwareAppCompatActivity() {
?.let { it as? TabTrayDialogFragment }
?.also { it.dismissAllowingStateLoss() }
}
// If there is a warm or hot startup, onNewIntent method is always called first.
// Note: This does not work in case of an user sending an intent with ACTION_VIEW
// for example, launch the application, and than use adb to send an intent with
// ACTION_VIEW to open a link. In this case, we will get multiple telemetry events.
intent
.toSafeIntent()
.let(::getIntentAllSource)
?.also { components.analytics.metrics.track(Event.AppRecievedIntent(it)) }
}
/**
@ -320,6 +333,14 @@ open class HomeActivity : LocaleAwareAppCompatActivity() {
}
}
protected open fun getIntentAllSource(intent: SafeIntent): Event.AppRecievedIntent.Source? {
return when {
intent.isLauncherIntent -> Event.AppRecievedIntent.Source.APP_ICON
intent.action == Intent.ACTION_VIEW -> Event.AppRecievedIntent.Source.LINK
else -> Event.AppRecievedIntent.Source.UNKNOWN
}
}
/**
* External sources such as 3rd party links and shortcuts use this function to enter
* private mode directly before the content view is created. Returns the mode set by the intent
@ -490,11 +511,6 @@ open class HomeActivity : LocaleAwareAppCompatActivity() {
}
}
fun updateThemeForSession(session: Session) {
val sessionMode = BrowsingMode.fromBoolean(session.private)
browsingModeManager.mode = sessionMode
}
override fun attachBaseContext(base: Context) {
StrictMode.allowThreadDiskReads().resetPoliciesAfter {
super.attachBaseContext(base)

View File

@ -9,8 +9,6 @@ import android.content.Intent
import android.os.Bundle
import android.os.StrictMode
import androidx.annotation.VisibleForTesting
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
import mozilla.components.feature.intent.processing.IntentProcessor
import org.mozilla.fenix.components.IntentProcessorType
import org.mozilla.fenix.components.getType
@ -33,19 +31,17 @@ class IntentReceiverActivity : Activity() {
super.onCreate(savedInstanceState)
}
MainScope().launch {
// The intent property is nullable, but the rest of the code below
// assumes it is not. If it's null, then we make a new one and open
// the HomeActivity.
val intent = intent?.let { Intent(it) } ?: Intent()
intent.stripUnwantedFlags()
processIntent(intent)
}
// The intent property is nullable, but the rest of the code below
// assumes it is not. If it's null, then we make a new one and open
// the HomeActivity.
val intent = intent?.let { Intent(it) } ?: Intent()
intent.stripUnwantedFlags()
processIntent(intent)
StartupTimeline.onActivityCreateEndIntentReceiver()
}
suspend fun processIntent(intent: Intent) {
fun processIntent(intent: Intent) {
// Call process for side effects, short on the first that returns true
val processor = getIntentProcessors().firstOrNull { it.process(intent) }
val intentProcessorType = components.intentProcessors.getType(processor)

View File

@ -78,6 +78,7 @@ import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.IntentReceiverActivity
import org.mozilla.fenix.NavGraphDirections
import org.mozilla.fenix.R
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.mozilla.fenix.browser.readermode.DefaultReaderModeController
import org.mozilla.fenix.components.FenixSnackbar
import org.mozilla.fenix.components.FindInPageIntegration
@ -690,7 +691,7 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
@CallSuper
override fun onSessionSelected(session: Session) {
(activity as HomeActivity).updateThemeForSession(session)
updateThemeForSession(session)
if (!browserInitialized) {
// Initializing a new coroutineScope to avoid ConcurrentModificationException in ObserverRegistry
// This will be removed when ObserverRegistry is deprecated by browser-state.
@ -720,6 +721,8 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
components.useCases.sessionUseCases.reload()
}
hideToolbar()
getSessionById()?.let { updateThemeForSession(it) }
}
@CallSuper
@ -872,6 +875,14 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
}
}
/**
* Set the activity normal/private theme to match the current session.
*/
private fun updateThemeForSession(session: Session) {
val sessionMode = BrowsingMode.fromBoolean(session.private)
(activity as HomeActivity).browsingModeManager.mode = sessionMode
}
/**
* Returns the current session.
*/
@ -997,6 +1008,5 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
private const val REQUEST_CODE_DOWNLOAD_PERMISSIONS = 1
private const val REQUEST_CODE_PROMPT_PERMISSIONS = 2
private const val REQUEST_CODE_APP_PERMISSIONS = 3
private const val SNACKBAR_ELEVATION = 80f
}
}

View File

@ -30,7 +30,6 @@ import mozilla.components.feature.tab.collections.TabCollection
import mozilla.components.feature.tabs.WindowFeature
import mozilla.components.support.base.feature.UserInteractionHandler
import mozilla.components.support.base.feature.ViewBoundFeatureWrapper
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.addons.runIfFragmentIsAttached
import org.mozilla.fenix.components.FenixSnackbar
@ -40,8 +39,8 @@ import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.nav
import org.mozilla.fenix.ext.navigateSafe
import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.ext.resetPoliciesAfter
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.shortcut.FirstTimePwaObserver
import org.mozilla.fenix.trackingprotection.TrackingProtectionOverlay
@ -178,9 +177,6 @@ class BrowserFragment : BaseBrowserFragment(), UserInteractionHandler {
override fun onResume() {
super.onResume()
getSessionById()?.let {
(activity as HomeActivity).updateThemeForSession(it)
}
requireComponents.core.tabCollectionStorage.register(collectionStorageObserver, this)
}

View File

@ -12,9 +12,12 @@ import mozilla.components.browser.session.SessionManager
import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.metrics
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.search.telemetry.ads.AdsTelemetry
import org.mozilla.fenix.utils.Settings
class UriOpenedObserver(
private val settings: Settings,
private val owner: LifecycleOwner,
private val sessionManager: SessionManager,
metrics: MetricController,
@ -22,6 +25,7 @@ class UriOpenedObserver(
) : SessionManager.Observer {
constructor(activity: FragmentActivity) : this(
activity.applicationContext.settings(),
activity,
activity.components.core.sessionManager,
activity.metrics,
@ -41,20 +45,24 @@ class UriOpenedObserver(
}
override fun onAllSessionsRemoved() {
settings.setOpenTabsCount(sessionManager.sessions.filter { !it.private }.size)
sessionManager.sessions.forEach {
it.unregister(singleSessionObserver)
}
}
override fun onSessionAdded(session: Session) {
settings.setOpenTabsCount(sessionManager.sessions.filter { !it.private }.size)
session.register(singleSessionObserver, owner)
}
override fun onSessionRemoved(session: Session) {
settings.setOpenTabsCount(sessionManager.sessions.filter { !it.private }.size)
session.unregister(singleSessionObserver)
}
override fun onSessionsRestored() {
settings.setOpenTabsCount(sessionManager.sessions.filter { !it.private }.size)
sessionManager.sessions.forEach {
it.register(singleSessionObserver, owner)
}

View File

@ -8,7 +8,6 @@ package org.mozilla.fenix.collections
import androidx.annotation.VisibleForTesting
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch
import mozilla.components.browser.session.Session
import mozilla.components.browser.session.SessionManager
@ -62,13 +61,21 @@ fun List<Tab>.toSessionBundle(sessionManager: SessionManager): List<Session> {
return this.mapNotNull { sessionManager.findSessionById(it.sessionId) }
}
/**
* @param store Store used to hold in-memory collection state.
* @param dismiss Callback to dismiss the collection creation dialog.
* @param metrics Controller that handles telemetry events.
* @param tabCollectionStorage Storage used to save tab collections to disk.
* @param sessionManager Used to query and serialize tabs.
* @param ioScope Coroutine scope that launches on the IO thread.
*/
class DefaultCollectionCreationController(
private val store: CollectionCreationStore,
private val dismiss: () -> Unit,
private val metrics: MetricController,
private val tabCollectionStorage: TabCollectionStorage,
private val sessionManager: SessionManager,
private val scope: CoroutineScope
private val ioScope: CoroutineScope
) : CollectionCreationController {
companion object {
@ -80,7 +87,7 @@ class DefaultCollectionCreationController(
dismiss()
val sessionBundle = tabs.toSessionBundle(sessionManager)
scope.launch(IO) {
ioScope.launch {
tabCollectionStorage.createCollection(name, sessionBundle)
}
@ -91,7 +98,7 @@ class DefaultCollectionCreationController(
override fun renameCollection(collection: TabCollection, name: String) {
dismiss()
scope.launch(IO) {
ioScope.launch {
tabCollectionStorage.renameCollection(collection, name)
}
metrics.track(Event.CollectionRenamed)
@ -121,7 +128,7 @@ class DefaultCollectionCreationController(
override fun selectCollection(collection: TabCollection, tabs: List<Tab>) {
dismiss()
val sessionBundle = tabs.toList().toSessionBundle(sessionManager)
scope.launch(IO) {
ioScope.launch {
tabCollectionStorage
.addTabsToCollection(collection, sessionBundle)
}

View File

@ -14,7 +14,9 @@ import androidx.fragment.app.DialogFragment
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.navArgs
import kotlinx.android.synthetic.main.fragment_create_collection.view.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.plus
import mozilla.components.browser.session.SessionManager
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.lib.publicsuffixlist.PublicSuffixList
@ -77,7 +79,7 @@ class CollectionCreationFragment : DialogFragment() {
requireComponents.analytics.metrics,
requireComponents.core.tabCollectionStorage,
requireComponents.core.sessionManager,
scope = lifecycleScope
ioScope = lifecycleScope + Dispatchers.IO
)
)
collectionCreationView = CollectionCreationView(

View File

@ -188,7 +188,7 @@ class Core(private val context: Context) {
WebNotificationFeature(
context, engine, icons, R.drawable.ic_status_logo,
HomeActivity::class.java
permissionStorage.permissionsStorage, HomeActivity::class.java
)
}
}

View File

@ -22,16 +22,15 @@ import org.mozilla.fenix.GleanMetrics.CustomTab
import org.mozilla.fenix.GleanMetrics.DownloadNotification
import org.mozilla.fenix.GleanMetrics.ErrorPage
import org.mozilla.fenix.GleanMetrics.Events
import org.mozilla.fenix.GleanMetrics.Events.preferenceToggled
import org.mozilla.fenix.GleanMetrics.FindInPage
import org.mozilla.fenix.GleanMetrics.History
import org.mozilla.fenix.GleanMetrics.Logins
import org.mozilla.fenix.GleanMetrics.MediaNotification
import org.mozilla.fenix.GleanMetrics.MediaState
import org.mozilla.fenix.GleanMetrics.Metrics
import org.mozilla.fenix.GleanMetrics.Onboarding
import org.mozilla.fenix.GleanMetrics.Pings
import org.mozilla.fenix.GleanMetrics.Pocket
import org.mozilla.fenix.GleanMetrics.Onboarding
import org.mozilla.fenix.GleanMetrics.Preferences
import org.mozilla.fenix.GleanMetrics.PrivateBrowsingMode
import org.mozilla.fenix.GleanMetrics.PrivateBrowsingShortcut
@ -98,6 +97,10 @@ private val Event.wrapper: EventWrapper<*>?
{ Events.appOpened.record(it) },
{ Events.appOpenedKeys.valueOf(it) }
)
is Event.AppRecievedIntent -> EventWrapper(
{ Events.appReceivedIntent.record(it) },
{ Events.appReceivedIntentKeys.valueOf(it) }
)
is Event.SearchBarTapped -> EventWrapper(
{ Events.searchBarTapped.record(it) },
{ Events.searchBarTappedKeys.valueOf(it) }
@ -602,6 +605,43 @@ private val Event.wrapper: EventWrapper<*>?
{ ContextualHintTrackingProtection.outsideTap.record(it) }
)
is Event.TabsTrayOpened -> EventWrapper<NoExtraKeys>(
{ org.mozilla.fenix.GleanMetrics.TabsTray.opened.record(it) }
)
is Event.TabsTrayClosed -> EventWrapper<NoExtraKeys>(
{ org.mozilla.fenix.GleanMetrics.TabsTray.closed.record(it) }
)
is Event.OpenedExistingTab -> EventWrapper<NoExtraKeys>(
{ org.mozilla.fenix.GleanMetrics.TabsTray.openedExistingTab.record(it) }
)
is Event.ClosedExistingTab -> EventWrapper<NoExtraKeys>(
{ org.mozilla.fenix.GleanMetrics.TabsTray.closedExistingTab.record(it) }
)
is Event.TabsTrayPrivateModeTapped -> EventWrapper<NoExtraKeys>(
{ org.mozilla.fenix.GleanMetrics.TabsTray.privateModeTapped.record(it) }
)
is Event.TabsTrayNormalModeTapped -> EventWrapper<NoExtraKeys>(
{ org.mozilla.fenix.GleanMetrics.TabsTray.normalModeTapped.record(it) }
)
is Event.NewTabTapped -> EventWrapper<NoExtraKeys>(
{ org.mozilla.fenix.GleanMetrics.TabsTray.newTabTapped.record(it) }
)
is Event.NewPrivateTabTapped -> EventWrapper<NoExtraKeys>(
{ org.mozilla.fenix.GleanMetrics.TabsTray.newPrivateTabTapped.record(it) }
)
is Event.TabsTrayMenuOpened -> EventWrapper<NoExtraKeys>(
{ org.mozilla.fenix.GleanMetrics.TabsTray.menuOpened.record(it) }
)
is Event.TabsTraySaveToCollectionPressed -> EventWrapper<NoExtraKeys>(
{ org.mozilla.fenix.GleanMetrics.TabsTray.saveToCollection.record(it) }
)
is Event.TabsTrayShareAllTabsPressed -> EventWrapper<NoExtraKeys>(
{ org.mozilla.fenix.GleanMetrics.TabsTray.shareAllTabs.record(it) }
)
is Event.TabsTrayCloseAllTabsPressed -> EventWrapper<NoExtraKeys>(
{ org.mozilla.fenix.GleanMetrics.TabsTray.closeAllTabs.record(it) }
)
// Don't record other events in Glean:
is Event.AddBookmark -> null
is Event.OpenedBookmark -> null
@ -661,6 +701,12 @@ class GleanMetricsService(private val context: Context) : MetricsService {
searchWidgetInstalled.set(context.settings().searchWidgetInstalled)
val openTabsCount = context.settings().openTabsCount
hasOpenTabs.set(openTabsCount > 0)
if (openTabsCount > 0) {
tabsOpenCount.add(openTabsCount)
}
val topSitesSize = context.settings().topSitesSize
hasTopSites.set(topSitesSize > 0)
if (topSitesSize > 0) {

View File

@ -185,6 +185,19 @@ sealed class Event {
object ContextualHintETPOutsideTap : Event()
object ContextualHintETPInsideTap : Event()
object TabsTrayOpened : Event()
object TabsTrayClosed : Event()
object OpenedExistingTab : Event()
object ClosedExistingTab : Event()
object TabsTrayPrivateModeTapped : Event()
object TabsTrayNormalModeTapped : Event()
object NewTabTapped : Event()
object NewPrivateTabTapped : Event()
object TabsTrayMenuOpened : Event()
object TabsTraySaveToCollectionPressed : Event()
object TabsTrayShareAllTabsPressed : Event()
object TabsTrayCloseAllTabsPressed : Event()
// Interaction events with extras
data class OnboardingToolbarPosition(val position: Position) : Event() {
enum class Position { TOP, BOTTOM }
@ -296,6 +309,13 @@ sealed class Event {
get() = hashMapOf(Events.appOpenedKeys.source to source.name)
}
data class AppRecievedIntent(val source: Source) : Event() {
enum class Source { APP_ICON, LINK, CUSTOM_TAB, UNKNOWN }
override val extras: Map<Events.appReceivedIntentKeys, String>?
get() = hashMapOf(Events.appReceivedIntentKeys.source to source.name)
}
data class CollectionSaveButtonPressed(val fromScreen: String) : Event() {
override val extras: Map<Collections.saveButtonKeys, String>?
get() = mapOf(Collections.saveButtonKeys.fromScreen to fromScreen)

View File

@ -19,6 +19,7 @@ import mozilla.components.browser.search.provider.SearchEngineList
import mozilla.components.browser.search.provider.SearchEngineProvider
import mozilla.components.browser.search.provider.filter.SearchEngineFilter
import mozilla.components.browser.search.provider.localization.LocaleSearchLocalizationProvider
import mozilla.components.browser.search.provider.localization.SearchLocalization
import mozilla.components.browser.search.provider.localization.SearchLocalizationProvider
import mozilla.components.service.location.LocationService
import mozilla.components.service.location.MozillaLocationService
@ -51,12 +52,18 @@ open class FenixSearchEngineProvider(
AssetsSearchEngineProvider(localizationProvider).loadSearchEngines(context)
}
private val loadedRegion = async { localizationProvider.determineRegion() }
// https://github.com/mozilla-mobile/fenix/issues/9935
// Adds a Locale search engine provider as a fallback in case the MLS lookup takes longer
// than the time it takes for a user to try to search.
private val fallBackEngines = async {
AssetsSearchEngineProvider(LocaleSearchLocalizationProvider()).loadSearchEngines(context)
}
private val fallbackLocationService: SearchLocalizationProvider = LocaleSearchLocalizationProvider()
private val fallBackProvider =
AssetsSearchEngineProvider(fallbackLocationService)
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
open val fallbackEngines = async { fallBackProvider.loadSearchEngines(context) }
private val fallbackRegion = async { fallbackLocationService.determineRegion() }
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
open val bundledSearchEngines = async {
@ -88,7 +95,15 @@ open class FenixSearchEngineProvider(
if (loadedSearchEngines.isCompleted) {
loadedSearchEngines
} else {
fallBackEngines
fallbackEngines
}
private val region: Deferred<SearchLocalization>
get() =
if (loadedRegion.isCompleted) {
loadedRegion
} else {
fallbackRegion
}
fun getDefaultEngine(context: Context): SearchEngine {
@ -199,7 +214,11 @@ open class FenixSearchEngineProvider(
}
if (!prefs.contains(installedEnginesKey)) {
val defaultSet = baseSearchEngines.await()
val searchEngines =
if (baseSearchEngines.isCompleted) baseSearchEngines
else fallbackEngines
val defaultSet = searchEngines.await()
.list
.map { it.identifier }
.toSet()
@ -215,7 +234,7 @@ open class FenixSearchEngineProvider(
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
suspend fun localeAwareInstalledEnginesKey(): String {
val tag = localizationProvider.determineRegion().let {
val tag = region.await().let {
val region = it.region?.let { region ->
if (region.isEmpty()) "" else "-$region"
}

View File

@ -67,7 +67,7 @@ class CustomTabsIntegration(
)
}
toolbar.background = getDrawable(activity, R.drawable.toolbar_background_private)
toolbar.background = getDrawable(activity, R.drawable.toolbar_background)
}
}

View File

@ -41,6 +41,8 @@ open class ExternalAppBrowserActivity : HomeActivity() {
final override fun getIntentSource(intent: SafeIntent) = Event.OpenedApp.Source.CUSTOM_TAB
final override fun getIntentAllSource(intent: SafeIntent) = Event.AppRecievedIntent.Source.CUSTOM_TAB
final override fun getIntentSessionId(intent: SafeIntent) = intent.getSessionId()
override fun getNavDirections(

View File

@ -9,6 +9,7 @@ import android.content.Intent
import android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT
import androidx.annotation.VisibleForTesting
import androidx.core.content.ContextCompat
import kotlinx.coroutines.runBlocking
import mozilla.components.browser.session.Session
import mozilla.components.browser.session.Session.Source
import mozilla.components.browser.session.SessionManager
@ -52,16 +53,17 @@ class FennecWebAppIntentProcessor(
* A custom tab config is also set so a custom tab toolbar can be shown when the user leaves
* the scope defined in the manifest.
*/
override suspend fun process(intent: Intent): Boolean {
override fun process(intent: Intent): Boolean {
val safeIntent = intent.toSafeIntent()
val url = safeIntent.dataString
return if (!url.isNullOrEmpty() && matches(intent)) {
val webAppManifest = loadManifest(safeIntent, url)
val webAppManifest = runBlocking { loadManifest(safeIntent, url) }
val session = Session(url, private = false, source = Source.HOME_SCREEN)
session.webAppManifest = webAppManifest
session.customTabConfig = webAppManifest?.toCustomTabConfig() ?: createFallbackCustomTabConfig()
session.customTabConfig =
webAppManifest?.toCustomTabConfig() ?: createFallbackCustomTabConfig()
sessionManager.add(session)
loadUrlUseCase(url, session, EngineSession.LoadUrlFlags.external())

View File

@ -35,7 +35,7 @@ class FennecBookmarkShortcutsIntentProcessor(
* If this is an Intent for a Fennec pinned website shortcut
* prepare it for opening website's URL in a new tab.
*/
override suspend fun process(intent: Intent): Boolean {
override fun process(intent: Intent): Boolean {
val safeIntent = intent.toSafeIntent()
val url = safeIntent.dataString

View File

@ -204,14 +204,14 @@ class BookmarkFragment : LibraryPageFragment<BookmarkNode>(), UserInteractionHan
R.id.open_bookmarks_in_new_tabs_multi_select -> {
openItemsInNewTab { node -> node.url }
navigate(BookmarkFragmentDirections.actionGlobalHome())
navigate(BookmarkFragmentDirections.actionGlobalTabTrayDialogFragment())
metrics?.track(Event.OpenedBookmarksInNewTabs)
true
}
R.id.open_bookmarks_in_private_tabs_multi_select -> {
openItemsInNewTab(private = true) { node -> node.url }
navigate(BookmarkFragmentDirections.actionGlobalHome())
navigate(BookmarkFragmentDirections.actionGlobalTabTrayDialogFragment())
metrics?.track(Event.OpenedBookmarksInPrivateTabs)
true
}

View File

@ -183,7 +183,7 @@ class HistoryFragment : LibraryPageFragment<HistoryItem>(), UserInteractionHandl
nav(
R.id.historyFragment,
HistoryFragmentDirections.actionGlobalHome()
HistoryFragmentDirections.actionGlobalTabTrayDialogFragment()
)
true
}
@ -199,7 +199,7 @@ class HistoryFragment : LibraryPageFragment<HistoryItem>(), UserInteractionHandl
}
nav(
R.id.historyFragment,
HistoryFragmentDirections.actionGlobalHome()
HistoryFragmentDirections.actionGlobalTabTrayDialogFragment()
)
true
}

View File

@ -294,8 +294,6 @@ class SearchFragment : Fragment(), UserInteractionHandler {
view.search_suggestions_onboarding.setOnInflateListener((stubListener))
view.toolbar_wrapper.clipToOutline = false
fill_link_from_clipboard.setOnClickListener {
(activity as HomeActivity)
.openToBrowserAndLoad(

View File

@ -8,7 +8,6 @@ import android.content.Context
import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable
import androidx.appcompat.content.res.AppCompatResources
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.content.ContextCompat
import mozilla.components.browser.domains.autocomplete.ShippedDomainsProvider
import mozilla.components.browser.toolbar.BrowserToolbar
@ -16,7 +15,6 @@ import mozilla.components.concept.engine.Engine
import mozilla.components.concept.storage.HistoryStorage
import mozilla.components.feature.toolbar.ToolbarAutocompleteFeature
import mozilla.components.support.ktx.android.content.getColorFromAttr
import mozilla.components.support.ktx.android.util.dpToPx
import mozilla.components.support.ktx.android.view.hideKeyboard
import org.mozilla.fenix.R
import org.mozilla.fenix.search.SearchFragmentState
@ -64,8 +62,6 @@ class ToolbarView(
view.apply {
editMode()
elevation = TOOLBAR_ELEVATION_IN_DP.dpToPx(resources.displayMetrics).toFloat()
setOnUrlCommitListener {
// We're hiding the keyboard as early as possible to prevent the engine view
// from resizing in case the BrowserFragment is being displayed before the
@ -80,8 +76,6 @@ class ToolbarView(
context, ThemeManager.resolveAttribute(R.attr.foundation, context)
)
layoutParams.height = CoordinatorLayout.LayoutParams.MATCH_PARENT
edit.hint = context.getString(R.string.search_hint)
edit.colors = edit.colors.copy(
@ -156,8 +150,4 @@ class ToolbarView(
view.edit.setIcon(icon, searchState.searchEngineSource.searchEngine.name)
}
companion object {
private const val TOOLBAR_ELEVATION_IN_DP = 16
}
}

View File

@ -12,7 +12,8 @@ import org.mozilla.fenix.ext.showToolbar
/**
* Lets the user customize Private browsing options.
*/
class SecretSettingsPreference : PreferenceFragmentCompat() {
class SecretSettingsFragment : PreferenceFragmentCompat() {
override fun onResume() {
super.onResume()
showToolbar(getString(R.string.preferences_debug_settings))

View File

@ -25,13 +25,13 @@ import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.crashes.CrashListActivity
import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.utils.Do
import org.mozilla.fenix.settings.SupportUtils
import org.mozilla.fenix.settings.about.AboutItemType.LICENSING_INFO
import org.mozilla.fenix.settings.about.AboutItemType.PRIVACY_NOTICE
import org.mozilla.fenix.settings.about.AboutItemType.RIGHTS
import org.mozilla.fenix.settings.about.AboutItemType.SUPPORT
import org.mozilla.fenix.settings.about.AboutItemType.WHATS_NEW
import org.mozilla.fenix.utils.Do
import org.mozilla.fenix.whatsnew.WhatsNew
import org.mozilla.geckoview.BuildConfig as GeckoViewBuildConfig
@ -145,39 +145,39 @@ class AboutFragment : Fragment(), AboutPageListener {
val context = requireContext()
return listOf(
AboutPageItem.Item(
AboutPageItem(
AboutItem.ExternalLink(
WHATS_NEW,
SupportUtils.getWhatsNewUrl(context)
), getString(R.string.about_whats_new, getString(R.string.app_name))
),
AboutPageItem.Item(
AboutPageItem(
AboutItem.ExternalLink(
SUPPORT,
SupportUtils.getSumoURLForTopic(context, SupportUtils.SumoTopic.HELP)
), getString(R.string.about_support)
),
AboutPageItem.Item(
AboutPageItem(
AboutItem.Crashes,
getString(R.string.about_crashes)
),
AboutPageItem.Item(
AboutPageItem(
AboutItem.ExternalLink(
PRIVACY_NOTICE,
SupportUtils.getMozillaPageUrl(SupportUtils.MozillaPage.PRIVATE_NOTICE)
), getString(R.string.about_privacy_notice)
),
AboutPageItem.Item(
AboutPageItem(
AboutItem.ExternalLink(
RIGHTS,
SupportUtils.getSumoURLForTopic(context, SupportUtils.SumoTopic.YOUR_RIGHTS)
), getString(R.string.about_know_your_rights)
),
AboutPageItem.Item(
AboutPageItem(
AboutItem.ExternalLink(LICENSING_INFO, ABOUT_LICENSE_URL),
getString(R.string.about_licensing_information)
),
AboutPageItem.Item(
AboutPageItem(
AboutItem.Libraries,
getString(R.string.about_other_open_source_libraries)
)

View File

@ -14,6 +14,4 @@ enum class AboutItemType {
WHATS_NEW, SUPPORT, PRIVACY_NOTICE, RIGHTS, LICENSING_INFO
}
sealed class AboutPageItem {
data class Item(val type: AboutItem, val title: String) : AboutPageItem()
}
data class AboutPageItem(val type: AboutItem, val title: String)

View File

@ -20,19 +20,16 @@ class AboutPageAdapter(private val listener: AboutPageListener) :
}
override fun onBindViewHolder(holder: AboutItemViewHolder, position: Int) {
holder.bind(getItem(position) as AboutPageItem.Item)
holder.bind(getItem(position))
}
private object DiffCallback : DiffUtil.ItemCallback<AboutPageItem>() {
override fun areItemsTheSame(oldItem: AboutPageItem, newItem: AboutPageItem) =
oldItem === newItem
oldItem.title == newItem.title
override fun areContentsTheSame(oldItem: AboutPageItem, newItem: AboutPageItem) =
when (oldItem) {
is AboutPageItem.Item ->
newItem is AboutPageItem.Item && oldItem.title == newItem.title
}
oldItem == newItem
}
}

View File

@ -17,7 +17,7 @@ class AboutItemViewHolder(
) : RecyclerView.ViewHolder(view) {
private val title = view.about_item_title
private lateinit var item: AboutPageItem.Item
private lateinit var item: AboutPageItem
init {
itemView.setOnClickListener {
@ -25,7 +25,7 @@ class AboutItemViewHolder(
}
}
fun bind(item: AboutPageItem.Item) {
fun bind(item: AboutPageItem) {
this.item = item
title.text = item.title
}

View File

@ -23,9 +23,8 @@ class LocaleAdapter(private val interactor: LocaleSettingsViewInteractor) :
private var selectedLocale: Locale = Locale.getDefault()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseLocaleViewHolder {
val view =
LayoutInflater.from(parent.context)
.inflate(R.layout.locale_settings_item, parent, false)
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.locale_settings_item, parent, false)
return when (viewType) {
ItemType.DEFAULT.ordinal -> SystemLocaleViewHolder(

View File

@ -10,7 +10,7 @@ import android.view.ViewGroup
import androidx.core.content.ContextCompat.getColor
import androidx.core.view.isVisible
import kotlinx.android.extensions.LayoutContainer
import kotlinx.android.synthetic.main.quicksettings_website_info.view.*
import kotlinx.android.synthetic.main.quicksettings_website_info.*
import mozilla.components.support.ktx.android.content.getDrawableWithTint
import org.mozilla.fenix.R
@ -19,13 +19,14 @@ import org.mozilla.fenix.R
*
* Currently it does not support any user interaction.
*
* @param containerView [ViewGroup] in which this View will inflate itself.
* @param container [ViewGroup] in which this View will inflate itself.
*/
class WebsiteInfoView(
override val containerView: ViewGroup
container: ViewGroup
) : LayoutContainer {
val view: View = LayoutInflater.from(containerView.context)
.inflate(R.layout.quicksettings_website_info, containerView, true)
override val containerView: View = LayoutInflater.from(container.context)
.inflate(R.layout.quicksettings_website_info, container, true)
/**
* Allows changing what this View displays.
@ -39,25 +40,25 @@ class WebsiteInfoView(
bindCertificateName(state.certificateName)
}
private fun bindUrl(url: String) {
view.url.text = url
private fun bindUrl(websiteUrl: String) {
url.text = websiteUrl
}
private fun bindTitle(title: String) {
view.title.text = title
private fun bindTitle(websiteTitle: String) {
title.text = websiteTitle
}
private fun bindCertificateName(cert: String) {
val certificateLabel = view.context.getString(R.string.certificate_info_verified_by, cert)
view.certificateInfo.text = certificateLabel
view.certificateInfo.isVisible = cert.isNotEmpty()
val certificateLabel = containerView.context.getString(R.string.certificate_info_verified_by, cert)
certificateInfo.text = certificateLabel
certificateInfo.isVisible = cert.isNotEmpty()
}
private fun bindSecurityInfo(uiValues: WebsiteSecurityUiValues) {
val tint = getColor(view.context, uiValues.iconTintRes)
view.securityInfo.setText(uiValues.securityInfoRes)
view.securityInfoIcon.setImageDrawable(
view.context.getDrawableWithTint(uiValues.iconRes, tint)
val tint = getColor(containerView.context, uiValues.iconTintRes)
securityInfo.setText(uiValues.securityInfoRes)
securityInfoIcon.setImageDrawable(
containerView.context.getDrawableWithTint(uiValues.iconRes, tint)
)
}
}

View File

@ -28,7 +28,7 @@ class NewTabShortcutIntentProcessor : IntentProcessor {
* @param intent The intent to process.
* @return True if the intent was processed, otherwise false.
*/
override suspend fun process(intent: Intent): Boolean {
override fun process(intent: Intent): Boolean {
val safeIntent = SafeIntent(intent)
val (searchExtra, startPrivateMode) = when (safeIntent.action) {
ACTION_OPEN_TAB -> StartSearchIntentProcessor.STATIC_SHORTCUT_NEW_TAB to false

View File

@ -10,11 +10,13 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatDialogFragment
import androidx.core.view.isVisible
import androidx.core.view.updatePadding
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import kotlinx.android.synthetic.main.component_tabstray.view.*
import kotlinx.android.synthetic.main.component_tabstray_fab.view.*
import kotlinx.android.synthetic.main.fragment_tab_tray_dialog.*
import kotlinx.android.synthetic.main.fragment_tab_tray_dialog.view.*
import mozilla.components.browser.session.Session
@ -31,6 +33,7 @@ import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.components.FenixSnackbar
import org.mozilla.fenix.components.TabCollectionStorage
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.utils.allowUndo
@ -42,6 +45,10 @@ class TabTrayDialogFragment : AppCompatDialogFragment() {
private val tabTrayView: TabTrayView
get() = _tabTrayView!!
private val snackbarAnchor: View?
get() = if (tabTrayView.fabView.new_tab_button.isVisible) tabTrayView.fabView.new_tab_button
else null
private val collectionStorageObserver = object : TabCollectionStorage.Observer {
override fun onCollectionCreated(title: String, sessions: List<Session>) {
showCollectionSnackbar()
@ -54,11 +61,13 @@ class TabTrayDialogFragment : AppCompatDialogFragment() {
private val selectTabUseCase = object : TabsUseCases.SelectTabUseCase {
override fun invoke(tabId: String) {
requireContext().components.analytics.metrics.track(Event.OpenedExistingTab)
requireComponents.useCases.tabsUseCases.selectTab(tabId)
navigateToBrowser()
}
override fun invoke(session: Session) {
requireContext().components.analytics.metrics.track(Event.OpenedExistingTab)
requireComponents.useCases.tabsUseCases.selectTab(session)
navigateToBrowser()
}
@ -66,11 +75,13 @@ class TabTrayDialogFragment : AppCompatDialogFragment() {
private val removeTabUseCase = object : TabsUseCases.RemoveTabUseCase {
override fun invoke(sessionId: String) {
requireContext().components.analytics.metrics.track(Event.ClosedExistingTab)
showUndoSnackbarForTab(sessionId)
requireComponents.useCases.tabsUseCases.removeTab(sessionId)
}
override fun invoke(session: Session) {
requireContext().components.analytics.metrics.track(Event.ClosedExistingTab)
showUndoSnackbarForTab(session.id)
requireComponents.useCases.tabsUseCases.removeTab(session)
}
@ -134,6 +145,7 @@ class TabTrayDialogFragment : AppCompatDialogFragment() {
)
tabLayout.setOnClickListener {
requireContext().components.analytics.metrics.track(Event.TabsTrayClosed)
dismissAllowingStateLoss()
}
@ -182,7 +194,8 @@ class TabTrayDialogFragment : AppCompatDialogFragment() {
sessionManager.add(snapshot.session, isSelected, engineSessionState = state)
},
operation = { },
elevation = ELEVATION
elevation = ELEVATION,
anchorView = snackbarAnchor
)
}
}
@ -226,7 +239,8 @@ class TabTrayDialogFragment : AppCompatDialogFragment() {
context?.components?.core?.sessionManager?.restore(snapshot)
},
operation = { },
elevation = ELEVATION
elevation = ELEVATION,
anchorView = snackbarAnchor
)
}
}
@ -239,6 +253,7 @@ class TabTrayDialogFragment : AppCompatDialogFragment() {
isDisplayedWithBrowserToolbar = true,
view = (view as View)
)
.setAnchorView(snackbarAnchor)
.setText(requireContext().getString(R.string.create_collection_tabs_saved))
.setAction(requireContext().getString(R.string.create_collection_view)) {
dismissAllowingStateLoss()

View File

@ -30,6 +30,7 @@ import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.state.TabSessionState
import mozilla.components.browser.tabstray.BrowserTabsTray
import org.mozilla.fenix.R
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.settings
@ -64,6 +65,8 @@ class TabTrayView(
get() = container
init {
container.context.components.analytics.metrics.track(Event.TabsTrayOpened)
val hasAccessibilityEnabled = view.context.settings().accessibilityServicesEnabled
toggleFabText(isPrivate)
@ -81,6 +84,7 @@ class TabTrayView(
override fun onStateChanged(bottomSheet: View, newState: Int) {
if (newState == BottomSheetBehavior.STATE_HIDDEN) {
container.context.components.analytics.metrics.track(Event.TabsTrayClosed)
interactor.onTabTrayDismissed()
}
}
@ -154,6 +158,7 @@ class TabTrayView(
}
view.tab_tray_overflow.setOnClickListener {
container.context.components.analytics.metrics.track(Event.TabsTrayMenuOpened)
menu = tabTrayItemMenu.menuBuilder.build(container.context)
menu?.show(it)
?.also { pu ->
@ -167,6 +172,7 @@ class TabTrayView(
view.tab_tray_new_tab.apply {
isVisible = hasAccessibilityEnabled
setOnClickListener {
sendNewTabEvent(isPrivateModeSelected)
interactor.onNewTabTapped(isPrivateModeSelected)
}
}
@ -174,11 +180,22 @@ class TabTrayView(
fabView.new_tab_button.apply {
isVisible = !hasAccessibilityEnabled
setOnClickListener {
sendNewTabEvent(isPrivateModeSelected)
interactor.onNewTabTapped(isPrivateModeSelected)
}
}
}
private fun sendNewTabEvent(isPrivateModeSelected: Boolean) {
val eventToSend = if (isPrivateModeSelected) {
Event.NewPrivateTabTapped
} else {
Event.NewTabTapped
}
container.context.components.analytics.metrics.track(eventToSend)
}
fun expand() {
behavior.state = BottomSheetBehavior.STATE_EXPANDED
}
@ -195,6 +212,12 @@ class TabTrayView(
updateState(view.context.components.core.store.state)
scrollToSelectedTab()
if (isPrivateModeSelected) {
container.context.components.analytics.metrics.track(Event.TabsTrayPrivateModeTapped)
} else {
container.context.components.analytics.metrics.track(Event.TabsTrayNormalModeTapped)
}
}
override fun onTabReselected(tab: TabLayout.Tab?) { /*noop*/ }
@ -294,6 +317,7 @@ class TabTrayItemMenu(
context.getString(R.string.tab_tray_menu_item_save),
textColorResource = R.color.primary_text_normal_theme
) {
context.components.analytics.metrics.track(Event.TabsTraySaveToCollectionPressed)
onItemTapped.invoke(Item.SaveToCollection)
}.apply { visible = shouldShowSaveToCollection },
@ -301,6 +325,7 @@ class TabTrayItemMenu(
context.getString(R.string.tab_tray_menu_item_share),
textColorResource = R.color.primary_text_normal_theme
) {
context.components.analytics.metrics.track(Event.TabsTrayShareAllTabsPressed)
onItemTapped.invoke(Item.ShareAllTabs)
},
@ -308,6 +333,7 @@ class TabTrayItemMenu(
context.getString(R.string.tab_tray_menu_item_close),
textColorResource = R.color.primary_text_normal_theme
) {
context.components.analytics.metrics.track(Event.TabsTrayCloseAllTabsPressed)
onItemTapped.invoke(Item.CloseAllTabs)
}
)

View File

@ -309,7 +309,7 @@ class Settings private constructor(
val shouldShowSearchShortcuts by booleanPreference(
appContext.getPreferenceKey(R.string.pref_key_show_search_shortcuts),
default = true
default = false
)
val shouldUseDarkTheme by booleanPreference(
@ -775,6 +775,19 @@ class Settings private constructor(
default = 0
)
fun setOpenTabsCount(count: Int) {
preferences.edit().putInt(
appContext.getPreferenceKey(R.string.pref_key_open_tabs_count),
count
).apply()
}
val openTabsCount: Int
get() = preferences.getInt(
appContext.getPreferenceKey(R.string.pref_key_open_tabs_count),
0
)
private var savedLoginsSortingStrategyString by stringPreference(
appContext.getPreferenceKey(R.string.pref_key_saved_logins_sorting_strategy),
default = SavedLoginsFragment.SORTING_STRATEGY_ALPHABETICALLY

View File

@ -0,0 +1,9 @@
<?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/. -->
<translate
xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="0"
android:toXDelta="0"
android:duration="900" />

View File

@ -1,22 +0,0 @@
<?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/. -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<gradient
android:angle="45"
android:startColor="@color/toolbar_start_gradient_private_theme"
android:centerColor="@color/toolbar_center_gradient_private_theme"
android:endColor="@color/toolbar_end_gradient_private_theme"
android:type="linear" />
</shape>
</item>
<item android:gravity="top">
<shape android:shape="rectangle">
<size android:height="1dp" />
<solid android:color="@color/neutral_faded_private_theme" />
</shape>
</item>
</layer-list>

View File

@ -46,10 +46,9 @@
android:layout_height="wrap_content"
android:layout_below="@id/displayName"
android:layout_alignStart="@id/displayName"
android:textColor="?secondaryText"
android:maxLines="4"
android:text="@string/preferences_account_default_name"
android:textColor="?primaryText"
app:fontFamily="@font/metropolis_bold" />
android:text="@string/preferences_account_default_name" />
</RelativeLayout>

View File

@ -56,7 +56,7 @@
android:ellipsize="end"
android:maxLines="2"
android:minLines="2"
android:textAppearance="@style/SubtitleTextStyle"
android:textColor="?secondaryText"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/collection_item"
app:layout_constraintStart_toStartOf="@+id/collection_item"

View File

@ -47,6 +47,7 @@
android:textAllCaps="false"
android:textColor="@color/neutral_text"
android:textSize="16sp"
android:fontFamily="@font/metropolis_bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1"
app:layout_constraintStart_toEndOf="@+id/guideline"
@ -163,7 +164,7 @@
android:text="@string/create_collection_save_to_collection_empty"
android:textColor="?neutral"
android:textSize="16sp"
android:textStyle="bold"
android:fontFamily="@font/metropolis_semibold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/save_button"
app:layout_constraintStart_toEndOf="@id/bottom_bar_icon_button"
@ -176,7 +177,8 @@
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:text="@string/create_collection_save"
android:textColor="?neutral"
android:textColor="@color/photonWhite"
app:fontFamily="@font/metropolis_medium"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />

View File

@ -140,6 +140,7 @@
android:gravity="center_vertical"
android:singleLine="true"
android:text="@string/create_collection_add_new_collection"
android:fontFamily="@font/metropolis"
android:textColor="?neutral"
android:textSize="16sp"
android:textStyle="bold"

View File

@ -6,7 +6,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/history_wrapper"
android:id="@+id/synced_tabs_wrapper"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
@ -43,7 +43,7 @@
android:id="@+id/synced_tabs_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="@layout/history_list_item"/>
tools:listitem="@layout/sync_tabs_list_item"/>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -11,38 +11,24 @@
android:background="?foundation"
tools:context=".search.SearchFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/toolbar_wrapper"
<mozilla.components.browser.toolbar.BrowserToolbar
android:id="@+id/toolbar"
android:layout_width="0dp"
android:layout_height="@dimen/browser_toolbar_height"
android:layout_margin="0dp"
android:outlineProvider="paddedBounds"
android:background="@drawable/toolbar_background_top"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true"
app:layout_scrollFlags="scroll|enterAlways|snap|exitUntilCollapsed"
app:browserToolbarClearColor="?primaryText"
app:browserToolbarInsecureColor="?primaryText"
app:browserToolbarMenuColor="?primaryText"
app:browserToolbarProgressBarGravity="bottom"
app:browserToolbarSecureColor="?primaryText"
app:browserToolbarTrackingProtectionAndSecurityIndicatorSeparatorColor="?toolbarDivider"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<mozilla.components.browser.toolbar.BrowserToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="@dimen/browser_toolbar_height"
android:layout_gravity="top"
android:background="@drawable/toolbar_background_top"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true"
app:layout_scrollFlags="scroll|enterAlways|snap|exitUntilCollapsed"
app:browserToolbarClearColor="?primaryText"
app:browserToolbarInsecureColor="?primaryText"
app:browserToolbarMenuColor="?primaryText"
app:browserToolbarProgressBarGravity="bottom"
app:browserToolbarSecureColor="?primaryText"
app:browserToolbarTrackingProtectionAndSecurityIndicatorSeparatorColor="?toolbarDivider"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
app:layout_constraintTop_toTopOf="parent"/>
<androidx.core.widget.NestedScrollView
android:layout_width="0dp"
@ -51,7 +37,7 @@
app:layout_constraintBottom_toBottomOf="@id/search_divider"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolbar_wrapper">
app:layout_constraintTop_toBottomOf="@id/toolbar">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/scrollable_area"

View File

@ -14,14 +14,14 @@
<TextView
android:id="@+id/details_blocking_header"
style="@style/QuickSettingsText"
android:fontFamily="@font/metropolis_bold"
android:layout_width="wrap_content"
android:layout_height="@dimen/tracking_protection_item_height"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:paddingStart="0dp"
android:paddingEnd="0dp"
android:text="@string/enhanced_tracking_protection_blocked"
android:textStyle="bold" />
android:text="@string/enhanced_tracking_protection_blocked" />
<org.mozilla.fenix.trackingprotection.TrackingProtectionCategoryItem
android:id="@+id/category_social_media"

View File

@ -20,8 +20,9 @@
android:id="@+id/header_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="17sp"
android:textSize="14sp"
android:textColor="?primaryText"
android:fontFamily="@font/metropolis_semibold"
android:paddingStart="20dp"
android:paddingEnd="0dp"
android:layout_marginBottom="8dp"

View File

@ -30,10 +30,8 @@
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="@string/no_collections_description1"
android:textColor="?primaryText"
android:textSize="14sp"
android:textAlignment="viewStart"
app:fontFamily="@font/metropolis_medium" />
android:textAlignment="viewStart" />
<com.google.android.material.button.MaterialButton
android:id="@+id/add_tabs_to_collections_button"

View File

@ -8,34 +8,31 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="60dp"
android:paddingEnd="20dp"
android:minHeight="@dimen/library_item_height"
android:background="?android:attr/selectableItemBackground">
<TextView
android:id="@+id/synced_tab_item_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:ellipsize="end"
android:layout_marginStart="72dp"
android:layout_marginEnd="48dp"
android:layout_marginTop="6dp"
android:singleLine="true"
android:textAlignment="viewStart"
android:textColor="?primaryText"
android:textSize="18sp"
app:layout_constraintBottom_toTopOf="@+id/synced_tab_item_url"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="Tab Title" />
<TextView
android:id="@+id/synced_tab_item_url"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:ellipsize="end"
android:layout_marginStart="72dp"
android:layout_marginEnd="48dp"
android:layout_marginTop="2dp"
android:singleLine="true"
android:textAlignment="viewStart"
android:textColor="?secondaryText"
@ -43,21 +40,18 @@
tools:text="https://example.com/"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/synced_tab_item_title"
app:layout_constraintBottom_toBottomOf="parent" />
app:layout_constraintTop_toBottomOf="@+id/synced_tab_item_title" />
<View
android:id="@+id/synced_tab_item_separator"
android:layout_width="0dp"
android:layout_height="2dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="7dp"
android:background="?syncedTabsSeparator"
android:importantForAccessibility="no"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:visibility="invisible"
app:layout_constraintEnd_toEndOf="parent"
android:background="?neutralFaded"
android:visibility="gone"/>
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/synced_tab_item_url" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -29,10 +29,20 @@
android:layout_height="69dp"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:backgroundTint="?tabTrayThumbnailItemBackground"
app:cardBackgroundColor="@color/photonWhite"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/default_tab_thumbnail"
android:src="@drawable/mozac_ic_globe"
android:tint="?tabTrayThumbnailIcon"
android:padding="22dp"
android:importantForAccessibility="no"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<mozilla.components.browser.tabstray.thumbnail.TabThumbnailView
android:id="@+id/mozac_browser_tabstray_thumbnail"
android:layout_width="match_parent"

View File

@ -2,30 +2,39 @@
<!-- 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/. -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/synced_tabs_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingBottom="8dp"
android:paddingStart="16dp"
android:paddingEnd="16dp">
android:layout_marginTop="8dp">
<TextView
android:id="@+id/synced_tabs_group_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawablePadding="15dp"
app:drawableStartCompat="@drawable/mozac_ic_device_desktop"
app:drawableTint="?primaryText"
android:textSize="17sp"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:drawablePadding="32dp"
android:textAppearance="@style/Header14TextStyle"
android:textColor="?primaryText"
android:paddingStart="20dp"
android:paddingEnd="0dp"
android:layout_marginBottom="8dp"
android:textSize="12sp"
android:gravity="center"
app:drawableStartCompat="@drawable/mozac_ic_device_desktop"
app:drawableTint="?primaryText"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Header" />
</RelativeLayout>
<View
android:id="@+id/synced_tabs_group_separator"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="6dp"
android:background="?syncedTabsSeparator"
android:importantForAccessibility="no"
android:visibility="visible"
app:layout_constraintTop_toBottomOf="@+id/synced_tabs_group_name" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -544,7 +544,7 @@
android:name="org.mozilla.fenix.settings.about.AboutFragment"/>
<fragment
android:id="@+id/secretSettingsPreference"
android:name="org.mozilla.fenix.settings.SecretSettingsPreference"
android:name="org.mozilla.fenix.settings.SecretSettingsFragment"
android:label="@string/preferences_debug_settings" />
<fragment
android:id="@+id/crashReporterFragment"

View File

@ -58,12 +58,17 @@
<color name="tab_tray_item_media_background_normal_theme">@color/tab_tray_item_media_background_dark_theme</color>
<color name="tab_tray_heading_icon_normal_theme">@color/tab_tray_heading_icon_dark_theme</color>
<color name="tab_tray_heading_icon_inactive_normal_theme">@color/tab_tray_heading_icon_inactive_dark_theme</color>
<color name="tab_tray_item_thumbnail_background_normal_theme">@color/tab_tray_item_thumbnail_background_dark_theme</color>
<color name="tab_tray_item_thumbnail_icon_normal_theme">@color/tab_tray_item_thumbnail_icon_dark_theme</color>
<!--Top site colors -->
<color name="top_site_background">@color/top_site_background_dark_theme</color>
<color name="top_site_border">@color/top_site_border_dark_theme</color>
<color name="top_site_title_text">@color/top_site_title_text_dark_theme</color>
<!-- Synced tabs colors-->
<color name="synced_tabs_separator">@color/synced_tabs_separator_dark_theme</color>
<!-- Collection icons-->
<color name="collection_icon_color_violet">@color/collection_icon_color_violet_dark_theme</color>
<color name="collection_icon_color_blue">@color/collection_icon_color_blue_dark_theme</color>

View File

@ -1062,24 +1062,139 @@
<string name="sign_in_with_camera">Gāyì\'ì sēsiûn ngà si kamarât</string>
<!-- Text shown for settings option for sign with email -->
<string name="sign_in_with_email">Gārāsun si kōrreôt si lūgaj</string>
<!-- Text shown in confirmation dialog to sign out of account -->
<string name="sign_out_confirmation_message">Dūnâj Firefox si nāgi\'iaj nūguàn\'anj si kuentât, sanī si dure\'ej nej datô râj sunt ngà aché nunt riña aga\' nan.</string>
<!-- Text shown in confirmation dialog to sign out of account. The first parameter is the name of the app (e.g. Firefox Preview) -->
<string name="sign_out_confirmation_message_2">Dūnâj %s si nāgi\'iaj nūguàn\'anj si kuentât, sanī si dure\'ej nej datô râj sunt ngà aché nunt riña aga\' nan.</string>
<!-- Option to continue signing out of account shown in confirmation dialog to sign out of account -->
<string name="sign_out_disconnect">Gāhuī riña internet</string>
<!-- Option to cancel signing out shown in confirmation dialog to sign out of account -->
<string name="sign_out_cancel">Dūyichin\'</string>
<!-- Error message snackbar shown after the user tried to select a default folder which cannot be altered -->
<string name="bookmark_cannot_edit_root">Sī ga\'ue nādūnāt sa mà riña nej karpetâ ngà nīka \'naj</string>
<!-- Enhanced Tracking Protection -->
<!-- Link displayed in enhanced tracking protection panel to access tracking protection settings -->
<string name="etp_settings">Riña gā\'ue nāgi\'iát riña sa dugumî sò\'</string>
<!-- Preference title for enhanced tracking protection settings -->
<string name="preference_enhanced_tracking_protection">Sa huā hue\'ê doj guendâ nārán riña sa naga\'nāj a</string>
<!-- Title for the description of enhanced tracking protection -->
<string name="preference_enhanced_tracking_protection_explanation_title">Nitāj gà\' \'ngō ganikò\' sò\' si gāchē nunt</string>
<!-- Description of enhanced tracking protection. The first parameter is the name of the application (For example: Fenix) -->
<string name="preference_enhanced_tracking_protection_explanation">Duguminj nej si datôt. %s naran rayi\'ît riña nej sa naga\'nāj sa \'iát nga aché nunt.</string>
<!-- Text displayed that links to website about enhanced tracking protection -->
<string name="preference_enhanced_tracking_protection_explanation_learn_more">Gāhuin chrūn doj</string>
<!-- Preference for enhanced tracking protection for the standard protection settings -->
<string name="preference_enhanced_tracking_protection_standard_default_1">Sa huā chre\' (dàj huaj \'naj)</string>
<!-- Preference description for enhanced tracking protection for the standard protection settings -->
<string name="preference_enhanced_tracking_protection_standard_description_3">Riña dòj sa naga\'nāj a naran. Dàj rû\' nayi\'nïnj riña pâjina nāyi\'nïn nīñanj.</string>
<!-- Accessibility text for the Standard protection information icon -->
<string name="preference_enhanced_tracking_protection_standard_info_button">Ahuin si riñā narán sa dugumî sò\' \'na\' niñā guendâ nej sa naga\'nāj a</string>
<!-- Preference for enhanced tracking protection for the strict protection settings -->
<string name="preference_enhanced_tracking_protection_strict">Sa nùkuaj doj</string>
<!-- Preference description for enhanced tracking protection for the strict protection settings -->
<string name="preference_enhanced_tracking_protection_strict_description_2">Narán man riña doj sa naga\'nāj a, nej nuguan\' nata\'a nī nej bēntanâ narugui\' man\'an. Hìo doj nayî\'nïnj riña nej pâjina, sanī huā sa sī ga\'ue gi\'iaj sun hue\'e.</string>
<!-- Accessibility text for the Strict protection information icon -->
<string name="preference_enhanced_tracking_protection_strict_info_button">Ahuin si riñā narán sa nùkuaj doj dugumî sò\' \'na\' niñā guendâ nej sa naga\'nāj a</string>
<!-- Preference for enhanced tracking protection for the custom protection settings -->
<string name="preference_enhanced_tracking_protection_custom">Nāgi\'iaj mun\'ûn\'</string>
<!-- Preference description for enhanced tracking protection for the strict protection settings -->
<string name="preference_enhanced_tracking_protection_custom_description_2">Nāguī nej sa naga\'nāj a asi a\'ngô sa riñā ruhuât naránt.</string>
<!-- Accessibility text for the Strict protection information icon -->
<string name="preference_enhanced_tracking_protection_custom_info_button">Nan huin sa riñā narán sa dugumî sò\' \'na\' niñā guendâ nej sa naga\'nāj a</string>
<!-- Header for categories that are being blocked by current Enhanced Tracking Protection settings -->
<!-- Preference for enhanced tracking protection for the custom protection settings for cookies-->
<string name="preference_enhanced_tracking_protection_custom_cookies">Nej kôki</string>
<!-- Option for enhanced tracking protection for the custom protection settings for cookies-->
<string name="preference_enhanced_tracking_protection_custom_cookies_1">Sa naga\'nāj riña nej sîtio nī nej rêd sociâl</string>
<!-- Option for enhanced tracking protection for the custom protection settings for cookies-->
<string name="preference_enhanced_tracking_protection_custom_cookies_2">Si kokî nej sitiô nu atûjt</string>
<!-- Option for enhanced tracking protection for the custom protection settings for cookies-->
<string name="preference_enhanced_tracking_protection_custom_cookies_3">Daran\' nej kokî ânej e (ga\'ue gī\'iaj sun a\'nan\' web gī\'ia)</string>
<!-- Option for enhanced tracking protection for the custom protection settings for cookies-->
<string name="preference_enhanced_tracking_protection_custom_cookies_4">Daran\' nej kokî (ga\'ue dūre\'ej dā\'āj sîtio)</string>
<!-- Preference for enhanced tracking protection for the custom protection settings for tracking content -->
<string name="preference_enhanced_tracking_protection_custom_tracking_content">Sa nīkāj sa naga\'nāj a</string>
<!-- Option for enhanced tracking protection for the custom protection settings for tracking content-->
<string name="preference_enhanced_tracking_protection_custom_tracking_content_1">Riña daran\' nej rakïj ñanj</string>
<!-- Option for enhanced tracking protection for the custom protection settings for tracking content-->
<string name="preference_enhanced_tracking_protection_custom_tracking_content_2">Màn riña nej rakïj ñanj huìi</string>
<!-- Option for enhanced tracking protection for the custom protection settings for tracking content-->
<string name="preference_enhanced_tracking_protection_custom_tracking_content_3">Màn riña nej rakïj ñanj nagi\'iaj mān\'ânt</string>
<!-- Preference for enhanced tracking protection for the custom protection settings -->
<string name="preference_enhanced_tracking_protection_custom_cryptominers">Nej kriptominêro</string>
<!-- Preference for enhanced tracking protection for the custom protection settings -->
<string name="preference_enhanced_tracking_protection_custom_fingerprinters">Nej da\'nga\' rā\'a</string>
<string name="enhanced_tracking_protection_blocked">Nitāj si hūaj nāyi\'nïn</string>
<!-- Header for categories that are being not being blocked by current Enhanced Tracking Protection settings -->
<string name="enhanced_tracking_protection_allowed">Gā\'ue</string>
<!-- Category of trackers (social media trackers) that can be blocked by Enhanced Tracking Protection -->
<string name="etp_social_media_trackers_title">Nej sa naga\'nāj nej rêd sosiâl</string>
<!-- Description of social media trackers that can be blocked by Enhanced Tracking Protection -->
<string name="etp_social_media_trackers_description">Sī ga\'nïnjt riña nej rêd sōsiâl da\' nāga\'nāj nìko sa \'iát ngà aché nunt.</string>
<!-- Category of trackers (cross-site tracking cookies) that can be blocked by Enhanced Tracking Protection -->
<string name="etp_cookies_title">Nej kokî naga\'nāj riña nej dūguì\' nej sîtio</string>
<!-- Description of cross-site tracking cookies that can be blocked by Enhanced Tracking Protection -->
<string name="etp_cookies_description">Nārán riña nej kokî arâj sun nej rêd duyinga\' sa ane\'e nī nej dukuâ sun nadigi\'ñûn sa anïn ruhuâ guìi da\' si naga\'nāj nìko man nej sa \'iát nga aché nunt.</string>
<!-- Category of trackers (cryptominers) that can be blocked by Enhanced Tracking Protection -->
<string name="etp_cryptominers_title">Nej kriptominêro</string>
<!-- Description of cryptominers that can be blocked by Enhanced Tracking Protection -->
<string name="etp_cryptominers_description">Nu â\'nïn riña nej skripts yi\'ìi da\' gātū nej man riña si āgâ\'t nī gīrī nej man san\'ānj nānèe.</string>
<!-- Category of trackers (fingerprinters) that can be blocked by Enhanced Tracking Protection -->
<string name="etp_fingerprinters_title">Nej sa nani\'in nej da\'nga\' rā\'a</string>
<!-- Description of fingerprinters that can be blocked by Enhanced Tracking Protection -->
<string name="etp_fingerprinters_description">Nu â\'nïn da\' sī nari a\'ngô sa yi\'ìi nej nuguan\' nīkāj si āgâ\'t nī ga\'ue nāga\'nāj nej man sò\'.</string>
<!-- Category of trackers (tracking content) that can be blocked by Enhanced Tracking Protection -->
<string name="etp_tracking_content_title">Sa nīkāj sa naga\'nāj a</string>
<!-- Description of tracking content that can be blocked by Enhanced Tracking Protection -->
<string name="etp_tracking_content_description">Naran riña nej nuguan\' duyinga\' nej sa ane\'e, sa ni\'io\' nī riña nej nuguan\' nīkāj sa naga\'nāj a. Ga\'ue gā\'uì\' yī\'ij dàj \'iaj sun nej sîtio.</string>
<!-- Enhanced Tracking Protection Onboarding Message shown in a dialog above the toolbar. The first parameter is the name of the application (For example: Fenix) -->
<string name="etp_onboarding_cfr_message">Da\' nanûn kolô dînda riña eskûdo, ngà narán %s sa naga\'nāj riña \'ngō sitio. Gūru\'man ra\'a da\' gīni\'înt doj sa huā rayi\'î man.</string>
<!-- Enhanced Tracking Protection message that protection is currently on for this site -->
<string name="etp_panel_on">Ngà \'IAJ SUN nej sa dugumî sò\' riña sitiô nan</string>
<!-- Enhanced Tracking Protection message that protection is currently off for this site -->
<string name="etp_panel_off">NITĀJ SI \'IAJ SUN nej sa dugumî sò\' riña sitiô nan</string>
<!-- Header for exceptions list for which sites enhanced tracking protection is always off -->
<string name="enhanced_tracking_protection_exceptions">Nitāj si \'iaj sun sa nùkuaj narán riña sa naga\'nāj a riña nej sitiô nan</string>
<!-- Content description (not visible, for screen readers etc.): Navigate
back from ETP details (Ex: Tracking content) -->
<string name="etp_back_button_content_description">Gūij ne\' rūkùu</string>
<!-- About page Your rights link text -->
<string name="about_your_rights">Nej nuguan\' tna\'uēj rayi\'ît</string>
<!-- About page link text to open open source licenses screen -->
<string name="about_open_source_licenses">Dukuâ ñanj nīkāj kodigô huā nî\'nïnj arân sun ñûnj</string>
<!-- About page link text to open what's new link -->
<string name="about_whats_new">Sa nākà doj huā riña %s</string>
<!-- Open source licenses page title
The first parameter is the app name -->
<string name="open_source_licenses_title">%s Dukuâ ñanj OSS</string>
<!-- About page link text to open support link -->
<string name="about_support">Sa rugûñu\'ūnj un</string>
<!-- About page link text to list of past crashes (like about:crashes on desktop) -->
<string name="about_crashes">Nej sa gahui a\'nan\'</string>
<!-- About page link text to open privacy notice link -->
<string name="about_privacy_notice">Nuguan\' huì huin si dūkuan</string>
<!-- About page link text to open know your rights link -->
<string name="about_know_your_rights">Gīni\'in nej nuguan\' tna\'uēj rayi\'ît</string>
<!-- About page link text to open licensing information link -->
<string name="about_licensing_information">Si nùguàn\' līsênsia</string>
<!-- About page link text to open a screen with libraries that are used -->
<string name="about_other_open_source_libraries">Nej dukuâ ñanj arâj sun ñûnj</string>
<!-- Toast shown to the user when they are activating the secret dev menu
The first parameter is number of long clicks left to enable the menu -->
<string name="about_debug_menu_toast_progress">Menû nagi\'aj hìo: gūru\'man ra\'a %1$d da\' nāchrūnt</string>
<string name="about_debug_menu_toast_done">Menû nagi\'aj hìo ngà \'iaj sun</string>
<!-- Content description of the tab counter toolbar button when one tab is open -->
<string name="tab_counter_content_description_one_tab">1 rakïj ñanj</string>
<!-- Content description of the tab counter toolbar button when multiple tabs are open. First parameter will be replaced with the number of tabs (always more than one) -->
@ -1088,22 +1203,58 @@
<!-- Browser long press popup menu -->
<!-- Copy the current url -->
<string name="browser_toolbar_long_press_popup_copy">Gūxūn nī nāchrūnt a\'ngô hiūj u</string>
<!-- Paste & go the text in the clipboard. '&amp;' is replaced with the ampersand symbol: & -->
<string name="browser_toolbar_long_press_popup_paste_and_go">Gāchrūn &amp; Gūij</string>
<!-- Paste the text in the clipboard -->
<string name="browser_toolbar_long_press_popup_paste">Gāchrūn</string>
<!-- Snackbar message shown after an URL has been copied to clipboard. -->
<string name="browser_toolbar_url_copied_to_clipboard_snackbar">URL ngà nachîn riña portapapeles</string>
<!-- Title text for the Add To Homescreen dialog -->
<string name="add_to_homescreen_title">Gāchrūn man riña pantâya</string>
<!-- Cancel button text for the Add to Homescreen dialog -->
<string name="add_to_homescreen_cancel">Dūyichin\'</string>
<!-- Add button text for the Add to Homescreen dialog -->
<string name="add_to_homescreen_add">Nūtà\'</string>
<!-- Continue to website button text for the first-time Add to Homescreen dialog -->
<string name="add_to_homescreen_continue">Ginu ngè riña sitiô nan</string>
<!-- Placeholder text for the TextView in the Add to Homescreen dialog -->
<string name="add_to_homescreen_text_placeholder">Si yūgui aksêso dīrêkto</string>
<!-- Describes the add to homescreen functionality -->
<string name="add_to_homescreen_description">Gā\'ue nāchrūnt sitiô nan riña pajinâ ayi\'ìt riña aga\' a\'min nīkājt da\' ga\'ue hìo gātūt riñanj dàj rû\' \'iaj \'ngō aplikāsiûn</string>
<!-- Preference for managing the settings for logins and passwords in Fenix -->
<string name="preferences_passwords_logins_and_passwords">Nej riña gayi\'ìt sēsiûn nī nej da\'nga\' huìi</string>
<!-- Preference for managing the saving of logins and passwords in Fenix -->
<string name="preferences_passwords_save_logins">Nā\'nïnj sà\' nej riña gayi\'ìt sēsiûn nī nej da\'nga\' huìi</string>
<!-- Preference option for asking to save passwords in Fenix -->
<string name="preferences_passwords_save_logins_ask_to_save">Gāchìnj nì\'iaj nā\'nïnj sà\'t</string>
<!-- Preference option for never saving passwords in Fenix -->
<string name="preferences_passwords_save_logins_never_save">Nitāj āmān nā\'nïnj sà\'t</string>
<!-- Preference for autofilling saved logins in Fenix -->
<string name="preferences_passwords_autofill">Nāchra man\'an</string>
<!-- Preference for syncing saved logins in Fenix -->
<string name="preferences_passwords_sync_logins">Nāgi\'iaj nūguàn\'àn nej riña ayì\'ìt sēsiûn</string>
<!-- Syncing saved logins in Fenix is on -->
<string name="preferences_passwords_sync_logins_on">Nāchrūn</string>
<!-- Syncing saved logins in Fenix is off -->
<string name="preferences_passwords_sync_logins_off">Dūnâ\àj</string>
<!-- Syncing saved logins in Fenix needs reconnect to sync -->
<string name="preferences_passwords_sync_logins_reconnect">Gānātū ñû</string>
<!-- Syncing saved logins in Fenix needs login -->
<string name="preferences_passwords_sync_logins_sign_in">Gāyi\'ì sēsiûn riña Sync</string>
<!-- Preference to access list of saved logins -->
<string name="preferences_passwords_saved_logins">Sa gayi\'ìt sesiûn ngà naginu sà\'</string>
<!-- Learn more link that will link to a page with more information displayed when a connection is insecure and we detect the user is entering a password -->
<string name="logins_insecure_connection_warning_learn_more">Gāhuin chrūn doj</string>
<!-- Positive confirmation that Fenix should save the new or updated login -->
<string name="logins_doorhanger_save_confirmation">Nā\'nïnj sà\'</string>
<!-- Content description (not visible, for screen readers etc.): Title for the button to add a search engine in the action bar -->
<string name="search_engine_add_button_content_description">Nūtà\'</string>

View File

@ -51,6 +51,7 @@
<attr name="addOnPrivateBrowsingInteriorIconBackground" format="reference"/>
<attr name="readerModeStartGradient" format="reference"/>
<attr name="readerModeEndGradient" format="reference"/>
<attr name="syncedTabsSeparator" format="reference"/>
<!-- Tab tray -->
<attr name="tabTrayItemBackground" format="reference" />
@ -59,6 +60,8 @@
<attr name="tabTrayItemMediaBackground" format="reference" />
<attr name="tabTrayHeadingIcon" format="reference" />
<attr name="tabTrayHeadingIconInactive" format="reference" />
<attr name="tabTrayThumbnailItemBackground" format="reference" />
<attr name="tabTrayThumbnailIcon" format="reference" />
<declare-styleable name="TrackingProtectionCategory">
<attr name="categoryItemTitle" format="reference" />

View File

@ -47,6 +47,7 @@
<color name="dark_grey_90_gradient_end">#0015141A</color>
<color name="top_site_background_light_theme">@android:color/white</color>
<color name="top_site_border_light_theme">@color/light_grey_30</color>
<color name="synced_tabs_separator_light_theme">@color/light_grey_30</color>
<color name="top_site_title_text_light_theme">@color/light_grey_80</color>
<color name="collection_icon_color_violet_light_theme">#7542E5</color>
<color name="collection_icon_color_blue_light_theme">#0250BB</color>
@ -82,6 +83,8 @@
<color name="tab_tray_item_media_background_light_theme">#312A65</color>
<color name="tab_tray_heading_icon_light_theme">@color/ink_20</color>
<color name="tab_tray_heading_icon_inactive_light_theme">@color/ink_20_48a</color>
<color name="tab_tray_item_thumbnail_background_light_theme">@color/light_grey_10</color>
<color name="tab_tray_item_thumbnail_icon_light_theme">@color/light_grey_60</color>
<!-- Dark theme color palette -->
<color name="primary_text_dark_theme">#FBFBFE</color>
@ -104,6 +107,7 @@
<color name="scrimEnd_dark_theme">#F515141A</color>
<color name="top_site_background_dark_theme">@color/dark_grey_50</color>
<color name="top_site_border_dark_theme">@color/dark_grey_10</color>
<color name="synced_tabs_separator_dark_theme">@color/dark_grey_10</color>
<color name="top_site_title_text_dark_theme">@color/light_grey_90</color>
<color name="collection_icon_color_violet_dark_theme">#AB71FF</color>
<color name="collection_icon_color_blue_dark_theme">#00B3F4</color>
@ -138,6 +142,8 @@
<color name="tab_tray_item_media_background_dark_theme">#9059FF</color>
<color name="tab_tray_heading_icon_dark_theme">@color/violet_50</color>
<color name="tab_tray_heading_icon_inactive_dark_theme">@color/violet_50_48a</color>
<color name="tab_tray_item_thumbnail_background_dark_theme">@color/dark_grey_50</color>
<color name="tab_tray_item_thumbnail_icon_dark_theme">@color/dark_grey_05</color>
<!-- Private theme color palette -->
<color name="primary_text_private_theme">#FBFBFE</color>
@ -241,6 +247,8 @@
<color name="tab_tray_item_media_background_normal_theme">@color/tab_tray_item_media_background_light_theme</color>
<color name="tab_tray_heading_icon_normal_theme">@color/tab_tray_heading_icon_light_theme</color>
<color name="tab_tray_heading_icon_inactive_normal_theme">@color/tab_tray_heading_icon_inactive_light_theme</color>
<color name="tab_tray_item_thumbnail_background_normal_theme">@color/tab_tray_item_thumbnail_background_light_theme</color>
<color name="tab_tray_item_thumbnail_icon_normal_theme">@color/tab_tray_item_thumbnail_icon_light_theme</color>
<!-- Bookmark buttons -->
<color name="bookmark_favicon_background">#DFDFE3</color>
@ -250,6 +258,9 @@
<color name="top_site_border">@color/top_site_border_light_theme</color>
<color name="top_site_title_text">@color/top_site_title_text_light_theme</color>
<!-- Synced tabs colors-->
<color name="synced_tabs_separator">@color/synced_tabs_separator_light_theme</color>
<!-- Collection icons-->
<color name="collection_icon_color_violet">@color/collection_icon_color_violet_light_theme</color>
<color name="collection_icon_color_blue">@color/collection_icon_color_blue_light_theme</color>

View File

@ -79,7 +79,7 @@
<dimen name="search_fragment_clipboard_item_horizontal_margin">12dp</dimen>
<dimen name="search_fragment_clipboard_item_vertical_margin">8dp</dimen>
<dimen name="search_fragment_clipboard_item_title_margin_start">8dp</dimen>
<dimen name="search_fragment_shortcuts_label_margin_horizontal">8dp</dimen>
<dimen name="search_fragment_shortcuts_label_margin_horizontal">18dp</dimen>
<dimen name="search_fragment_shortcuts_label_margin_vertical">18dp</dimen>
<dimen name="search_fragment_pill_height">40dp</dimen>
<dimen name="search_fragment_pill_padding_start">20dp</dimen>

View File

@ -177,6 +177,8 @@
<string name="pref_key_debug_settings" translatable="false">pref_key_debug_settings</string>
<string name="pref_key_open_tabs_count" translatable="false">pref_key_open_tabs_count</string>
<string name="pref_key_search_count" translatable="false">pref_key_search_count</string>
<string name="pref_key_search_widget_cfr_display_count" translatable="false">pref_key_search_widget_cfr_display_count</string>
<string name="pref_key_search_widget_cfr_dismiss_count" translatable="false">pref_key_search_widget_cfr_dismiss_count</string>

View File

@ -20,6 +20,7 @@
<item name="alertDialogStyle">@style/DialogStyleNormal</item>
<item name="alertDialogTheme">@style/DialogStyleNormal</item>
<item name="android:windowEnableSplitTouch">false</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:splitMotionEvents">false</item>
<item name="mozacInputLayoutErrorTextColor"
@ -75,7 +76,7 @@
<item name="mozacPromptLoginEditTextCursorColor">@color/prompt_login_edit_text_cursor_color_normal_theme</item>
<item name="readerModeStartGradient">@color/readermode_start_gradient_normal_theme</item>
<item name="readerModeEndGradient">@color/readermode_end_gradient_normal_theme</item>
<item name="syncedTabsSeparator">@color/synced_tabs_separator</item>
<item name="tabTrayItemBackground">@color/tab_tray_item_background_normal_theme</item>
<item name="tabTrayItemSelectedBackground">@color/tab_tray_item_selected_background_normal_theme</item>
@ -83,6 +84,8 @@
<item name="tabTrayItemMediaBackground">@color/tab_tray_item_media_background_normal_theme</item>
<item name="tabTrayHeadingIcon">@color/tab_tray_heading_icon_normal_theme</item>
<item name="tabTrayHeadingIconInactive">@color/tab_tray_heading_icon_inactive_normal_theme</item>
<item name="tabTrayThumbnailItemBackground">@color/tab_tray_item_thumbnail_background_normal_theme</item>
<item name="tabTrayThumbnailIcon">@color/tab_tray_item_thumbnail_icon_normal_theme</item>
<!-- Drawables -->
<item name="fenixLogo">@drawable/ic_logo_wordmark_normal</item>
@ -208,6 +211,8 @@
<item name="tabTrayItemMediaBackground">@color/tab_tray_item_media_background_private_theme</item>
<item name="tabTrayHeadingIcon">@color/tab_tray_heading_icon_dark_theme</item>
<item name="tabTrayHeadingIconInactive">@color/tab_tray_heading_icon_inactive_dark_theme</item>
<item name="tabTrayThumbnailItemBackground">@color/tab_tray_item_thumbnail_background_normal_theme</item>
<item name="tabTrayThumbnailIcon">@color/tab_tray_item_thumbnail_icon_normal_theme</item>
<!-- Drawables -->
<item name="fenixLogo">@drawable/ic_logo_wordmark_private</item>
@ -445,7 +450,7 @@
</style>
<style name="SearchShortcutsLabelStyle">
<item name="android:fontFamily">Inter UI</item>
<item name="android:fontFamily">@font/metropolis_semibold</item>
<item name="android:letterSpacing">0.15</item>
<item name="android:textAllCaps">true</item>
<item name="android:textColor">?secondaryText</item>
@ -480,6 +485,7 @@
<item name="android:minHeight">40dp</item>
<item name="android:layout_marginTop">32dp</item>
<item name="android:textColor">?accentUsedOnDarkBackground</item>
<item name="android:fontFamily">@font/metropolis_semibold</item>
</style>
<style name="ShareHeaderTextStyle">

View File

@ -39,6 +39,6 @@ class MigrationDecisionActivity : Activity() {
// and then we switch to the actual activity without an animation. This visually looks like
// a faster start than launching this activity invisibly and switching to the actual
// activity after that.
overridePendingTransition(0, 0)
overridePendingTransition(0, R.anim.placeholder_animation)
}
}

View File

@ -16,9 +16,11 @@ import org.junit.Test
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.search.telemetry.ads.AdsTelemetry
import org.mozilla.fenix.utils.Settings
class TelemetrySessionObserverTest {
private val settings: Settings = mockk(relaxed = true)
private val owner: LifecycleOwner = mockk(relaxed = true)
private val sessionManager: SessionManager = mockk(relaxed = true)
private val metrics: MetricController = mockk(relaxed = true)
@ -29,7 +31,7 @@ class TelemetrySessionObserverTest {
@Before
fun setup() {
singleSessionObserver =
UriOpenedObserver(owner, sessionManager, metrics, ads).singleSessionObserver
UriOpenedObserver(settings, owner, sessionManager, metrics, ads).singleSessionObserver
}
@Test

View File

@ -11,11 +11,13 @@ import mozilla.components.browser.session.Session
import mozilla.components.browser.session.SessionManager
import org.junit.Before
import org.junit.Test
import org.mozilla.fenix.search.telemetry.ads.AdsTelemetry
import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.search.telemetry.ads.AdsTelemetry
import org.mozilla.fenix.utils.Settings
class UriOpenedObserverTest {
private val settings: Settings = mockk(relaxed = true)
private val owner: LifecycleOwner = mockk(relaxed = true)
private val sessionManager: SessionManager = mockk(relaxed = true)
private val metrics: MetricController = mockk()
@ -24,7 +26,7 @@ class UriOpenedObserverTest {
@Before
fun setup() {
observer = UriOpenedObserver(owner, sessionManager, metrics, ads)
observer = UriOpenedObserver(settings, owner, sessionManager, metrics, ads)
}
@Test

View File

@ -100,7 +100,7 @@ class IntentProcessorTypeTest {
@Test
fun `get type for generic intent processor`() {
val processor = object : IntentProcessor {
override suspend fun process(intent: Intent) = true
override fun process(intent: Intent) = true
}
val type = testContext.components.intentProcessors.getType(processor)

View File

@ -119,6 +119,21 @@ class FakeFenixSearchEngineProvider(context: Context) : FenixSearchEngineProvide
)
}
override val fallbackEngines: Deferred<SearchEngineList>
get() {
val google = mockSearchEngine(id = "google-b-1-m", n = "Google")
return CompletableDeferred(
SearchEngineList(
listOf(
google,
mockSearchEngine("bing", "Bing"),
mockSearchEngine("amazondotcom", "Amazon.com")
), default = google
)
)
}
override val bundledSearchEngines = CompletableDeferred(
SearchEngineList(
listOf(

View File

@ -150,6 +150,10 @@ class DefaultSearchControllerTest {
@Test
fun `show search shortcuts when setting enabled AND query empty`() {
val text = ""
testContext.settings().preferences
.edit()
.putBoolean(testContext.getString(R.string.pref_key_show_search_shortcuts), true)
.apply()
controller.handleTextChanged(text)
@ -160,6 +164,10 @@ class DefaultSearchControllerTest {
fun `show search shortcuts when setting enabled AND query equals url`() {
val text = "mozilla.org"
every { session?.url } returns "mozilla.org"
testContext.settings().preferences
.edit()
.putBoolean(testContext.getString(R.string.pref_key_show_search_shortcuts), true)
.apply()
assertEquals(text, session?.url)

View File

@ -17,20 +17,21 @@ import mozilla.components.support.test.robolectric.testContext
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.settings.about.viewholders.AboutItemViewHolder
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
import org.mozilla.fenix.settings.about.viewholders.AboutItemViewHolder
@RunWith(FenixRobolectricTestRunner::class)
class AboutPageAdapterTest {
private var aboutList: List<AboutPageItem> =
mutableListOf(
AboutPageItem.Item(
private val aboutList: List<AboutPageItem> =
listOf(
AboutPageItem(
AboutItem.ExternalLink(
AboutItemType.WHATS_NEW,
"https://mozilla.org"
), "Libraries"
),
AboutPageItem.Item(AboutItem.Libraries, "Libraries")
AboutPageItem(AboutItem.Libraries, "Libraries"),
AboutPageItem(AboutItem.Crashes, "Crashes")
)
private val listener: AboutPageListener = mockk(relaxed = true)
@ -47,7 +48,7 @@ class AboutPageAdapterTest {
adapter.submitList(aboutList)
assertEquals(2, adapter.itemCount)
assertEquals(3, adapter.itemCount)
}
@Test
@ -78,6 +79,6 @@ class AboutPageAdapterTest {
adapter.submitList(aboutList)
adapter.bindViewHolder(viewHolder, 1)
verify { viewHolder.bind(aboutList[1] as AboutPageItem.Item) }
verify { viewHolder.bind(aboutList[1]) }
}
}

View File

@ -22,7 +22,7 @@ import org.mozilla.fenix.settings.about.AboutPageListener
@RunWith(FenixRobolectricTestRunner::class)
class AboutItemViewHolderTest {
private val item = AboutPageItem.Item(AboutItem.Libraries, "Libraries")
private val item = AboutPageItem(AboutItem.Libraries, "Libraries")
private lateinit var view: View
private lateinit var listener: AboutPageListener

View File

@ -6,10 +6,13 @@ package org.mozilla.fenix.settings.account
import androidx.navigation.NavController
import androidx.navigation.NavDestination
import io.mockk.Called
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
import org.mozilla.fenix.R
@ -34,6 +37,7 @@ class AccountSettingsInteractorTest {
@Test
fun onChangeDeviceName() {
val store: AccountSettingsFragmentStore = mockk(relaxed = true)
val invalidNameResponse = mockk<() -> Unit>(relaxed = true)
val interactor = AccountSettingsInteractor(
mockk(),
@ -42,9 +46,28 @@ class AccountSettingsInteractorTest {
store
)
interactor.onChangeDeviceName("New Name") {}
assertTrue(interactor.onChangeDeviceName("New Name", invalidNameResponse))
verify { store.dispatch(AccountSettingsFragmentAction.UpdateDeviceName("New Name")) }
verify { invalidNameResponse wasNot Called }
}
@Test
fun onChangeDeviceNameSyncFalse() {
val store: AccountSettingsFragmentStore = mockk(relaxed = true)
val invalidNameResponse = mockk<() -> Unit>(relaxed = true)
val interactor = AccountSettingsInteractor(
mockk(),
mockk(),
{ false },
store
)
assertFalse(interactor.onChangeDeviceName("New Name", invalidNameResponse))
verify { store wasNot Called }
verify { invalidNameResponse() }
}
@Test

View File

@ -0,0 +1,59 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix.settings.quicksettings
import android.widget.FrameLayout
import androidx.core.view.isVisible
import kotlinx.android.synthetic.main.library_site_item.title
import kotlinx.android.synthetic.main.library_site_item.url
import kotlinx.android.synthetic.main.quicksettings_website_info.*
import mozilla.components.support.test.robolectric.testContext
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
@RunWith(FenixRobolectricTestRunner::class)
class WebsiteInfoViewTest {
private lateinit var view: WebsiteInfoView
@Before
fun setup() {
view = WebsiteInfoView(FrameLayout(testContext))
}
@Test
fun bindUrlAndTitle() {
view.update(WebsiteInfoState(
websiteUrl = "https://mozilla.org",
websiteTitle = "Mozilla",
websiteSecurityUiValues = WebsiteSecurityUiValues.SECURE,
certificateName = ""
))
assertEquals("https://mozilla.org", view.url.text)
assertEquals("Mozilla", view.title.text)
assertEquals("Secure Connection", view.securityInfo.text)
assertFalse(view.certificateInfo.isVisible)
}
@Test
fun bindCert() {
view.update(WebsiteInfoState(
websiteUrl = "https://mozilla.org",
websiteTitle = "Mozilla",
websiteSecurityUiValues = WebsiteSecurityUiValues.INSECURE,
certificateName = "Certificate"
))
assertEquals("Insecure Connection", view.securityInfo.text)
assertEquals("Verified By: Certificate", view.certificateInfo.text)
assertTrue(view.certificateInfo.isVisible)
}
}

View File

@ -254,7 +254,7 @@ class SettingsTest {
fun shouldShowSearchShortcuts() {
// When just created
// Then
assertTrue(settings.shouldShowSearchShortcuts)
assertFalse(settings.shouldShowSearchShortcuts)
}
@Test

View File

@ -3,5 +3,5 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
object AndroidComponents {
const val VERSION = "48.0.20200626130049"
const val VERSION = "48.0.20200626213814"
}

File diff suppressed because one or more lines are too long