1
0
Fork 0

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

master
blallo 2020-08-13 00:00:36 +02:00
commit 5419c2b08b
42 changed files with 366 additions and 164 deletions

View File

@ -29,6 +29,8 @@ import org.mozilla.fenix.ui.robots.DeepLinkRobot
* - fenix://urls_bookmarks — take the user to the bookmarks list
* - fenix://settings_logins — take the user to the settings page to do with logins (not the saved logins).
**/
@Ignore("All tests perma-failing, see: https://github.com/mozilla-mobile/fenix/issues/13491")
class DeepLinkTest {
private val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
private lateinit var mockWebServer: MockWebServer

View File

@ -5,6 +5,7 @@
import android.content.Context
import android.os.Bundle
import mozilla.components.browser.engine.gecko.autofill.GeckoLoginDelegateWrapper
import mozilla.components.browser.engine.gecko.ext.toContentBlockingSetting
import mozilla.components.browser.engine.gecko.glean.GeckoAdapter
import mozilla.components.concept.engine.EngineSession.TrackingProtectionPolicy
import mozilla.components.concept.storage.LoginsStorage
@ -50,8 +51,7 @@ object GeckoProvider {
val runtimeSettings = builder
.crashHandler(CrashHandlerService::class.java)
.telemetryDelegate(GeckoAdapter())
// TODO: Fix me!
// .contentBlocking(policy.toContentBlockingSetting())
.contentBlocking(policy.toContentBlockingSetting())
.aboutConfigEnabled(Config.channel.isBeta)
.debugLogging(Config.channel.isDebug)
.build()

View File

@ -28,7 +28,14 @@ class AppRequestInterceptor(private val context: Context) : RequestInterceptor {
): RequestInterceptor.InterceptionResponse? {
return context.components.services.appLinksInterceptor
.onLoadRequest(
engineSession, uri, lastUri, hasUserGesture, isSameDomain, isRedirect, isDirectNavigation, isSubframeRequest
engineSession,
uri,
lastUri,
hasUserGesture,
isSameDomain,
isRedirect,
isDirectNavigation,
isSubframeRequest
)
}

View File

@ -48,4 +48,9 @@ object FeatureFlags {
* Enables wait til first contentful paint
*/
val waitUntilPaintToDraw = Config.channel.isNightlyOrDebug
/**
* Enables downloads with external download managers.
*/
val externalDownloadManager = Config.channel.isNightlyOrDebug
}

View File

@ -252,10 +252,12 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
lifecycleScope.launch(IO) {
if (
settings().isDefaultBrowser() &&
settings().wasDefaultBrowserOnLastPause != settings().isDefaultBrowser()
settings().wasDefaultBrowserOnLastResume != settings().isDefaultBrowser()
) {
metrics.track(Event.ChangedToDefaultBrowser)
}
settings().wasDefaultBrowserOnLastResume = settings().isDefaultBrowser()
}
}
@ -264,11 +266,6 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
}
if (settings().wasDefaultBrowserOnLastPause != settings().isDefaultBrowser()
) {
settings().wasDefaultBrowserOnLastPause = settings().isDefaultBrowser()
}
super.onPause()
// Every time the application goes into the background, it is possible that the user

View File

@ -21,6 +21,7 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import androidx.preference.PreferenceManager
import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.fragment_browser.*
import kotlinx.android.synthetic.main.fragment_browser.view.*
@ -41,7 +42,6 @@ import mozilla.components.browser.state.selector.findTabOrCustomTabOrSelectedTab
import mozilla.components.browser.state.state.SessionState
import mozilla.components.browser.state.state.content.DownloadState
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.browser.thumbnails.BrowserThumbnails
import mozilla.components.concept.engine.prompt.ShareData
import mozilla.components.feature.accounts.FxaCapability
import mozilla.components.feature.accounts.FxaWebChannelFeature
@ -99,6 +99,7 @@ import org.mozilla.fenix.downloads.DynamicDownloadDialog
import org.mozilla.fenix.ext.accessibilityManager
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.enterToImmersiveMode
import org.mozilla.fenix.ext.getPreferenceKey
import org.mozilla.fenix.ext.hideToolbar
import org.mozilla.fenix.ext.metrics
import org.mozilla.fenix.ext.nav
@ -138,7 +139,6 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
private val appLinksFeature = ViewBoundFeatureWrapper<AppLinksFeature>()
private val promptsFeature = ViewBoundFeatureWrapper<PromptFeature>()
private val findInPageIntegration = ViewBoundFeatureWrapper<FindInPageIntegration>()
private val thumbnailsFeature = ViewBoundFeatureWrapper<BrowserThumbnails>()
private val toolbarIntegration = ViewBoundFeatureWrapper<ToolbarIntegration>()
private val sitePermissionsFeature = ViewBoundFeatureWrapper<SitePermissionsFeature>()
private val fullScreenFeature = ViewBoundFeatureWrapper<FullScreenFeature>()
@ -279,12 +279,6 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
lifecycleOwner = viewLifecycleOwner
)
thumbnailsFeature.set(
feature = BrowserThumbnails(context, view.engineView, store),
owner = this,
view = view
)
toolbarIntegration.set(
feature = browserToolbarView.toolbarIntegration,
owner = this,
@ -346,6 +340,11 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
view = view
)
val shouldForwardToThirdParties =
PreferenceManager.getDefaultSharedPreferences(context).getBoolean(
context.getPreferenceKey(R.string.pref_key_external_download_manager), false
)
val downloadFeature = DownloadsFeature(
context.applicationContext,
store = store,
@ -357,6 +356,7 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
store,
DownloadService::class
),
shouldForwardToThirdParties = { shouldForwardToThirdParties },
promptsStyling = DownloadsFeature.PromptsStyling(
gravity = Gravity.BOTTOM,
shouldWidthMatchParent = true,
@ -586,7 +586,7 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
.ifChanged { it.content.firstContentfulPaint }
.collect {
val showEngineView =
it.content.firstContentfulPaint || it.content.progress == 100
it.content.firstContentfulPaint || it.content.progress == LOADING_PROGRESS_COMPLETE
if (showEngineView) {
engineView?.asView()?.isVisible = true
@ -804,11 +804,8 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
}
override fun onBackLongPressed(): Boolean {
if (FeatureFlags.tabHistory) {
findNavController().navigate(R.id.action_global_tabHistoryDialogFragment)
return true
}
return false
findNavController().navigate(R.id.action_global_tabHistoryDialogFragment)
return true
}
/**
@ -1074,6 +1071,8 @@ 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 LOADING_PROGRESS_COMPLETE = 100
}
override fun onAccessibilityStateChanged(enabled: Boolean) {

View File

@ -42,7 +42,7 @@ class BrowserAnimator(
if (unwrappedSwipeRefresh?.context?.settings()?.waitToShowPageUntilFirstPaint == true) {
if (firstContentfulHappened()) {
viewLifecycleScope.get()?.launch {
delay(100)
delay(ANIMATION_DELAY)
unwrappedEngineView?.asView()?.visibility = View.VISIBLE
unwrappedSwipeRefresh?.background = null
unwrappedSwipeRefresh?.alpha = 1f
@ -91,6 +91,8 @@ class BrowserAnimator(
}
companion object {
private const val ANIMATION_DELAY = 100L
fun getToolbarNavOptions(context: Context): NavOptions {
val navOptions = NavOptions.Builder()

View File

@ -21,6 +21,7 @@ import kotlinx.android.synthetic.main.fragment_browser.view.*
import kotlinx.coroutines.ExperimentalCoroutinesApi
import mozilla.components.browser.session.Session
import mozilla.components.browser.state.selector.findTab
import mozilla.components.browser.thumbnails.BrowserThumbnails
import mozilla.components.browser.toolbar.BrowserToolbar
import mozilla.components.feature.app.links.AppLinksUseCases
import mozilla.components.feature.contextmenu.ContextMenuCandidate
@ -55,6 +56,7 @@ class BrowserFragment : BaseBrowserFragment(), UserInteractionHandler {
private val windowFeature = ViewBoundFeatureWrapper<WindowFeature>()
private val searchFeature = ViewBoundFeatureWrapper<SearchFeature>()
private val thumbnailsFeature = ViewBoundFeatureWrapper<BrowserThumbnails>()
private var readerModeAvailable = false
@ -107,6 +109,12 @@ class BrowserFragment : BaseBrowserFragment(), UserInteractionHandler {
browserToolbarView.view.addPageAction(readerModeAction)
thumbnailsFeature.set(
feature = BrowserThumbnails(context, view.engineView, components.core.store),
owner = this,
view = view
)
readerViewFeature.set(
feature = StrictMode.allowThreadDiskReads().resetPoliciesAfter {
ReaderViewFeature(

View File

@ -35,6 +35,7 @@ import kotlin.math.min
* Handles intercepting touch events on the toolbar for swipe gestures and executes the
* necessary animations.
*/
@Suppress("LargeClass", "TooManyFunctions")
class ToolbarGestureHandler(
private val activity: Activity,
private val contentLayout: View,
@ -76,6 +77,7 @@ class ToolbarGestureHandler(
GestureDirection.LEFT_TO_RIGHT
}
@Suppress("ComplexCondition")
return if (
!activity.window.decorView.isKeyboardVisible() &&
start.isInToolbar() &&

View File

@ -95,6 +95,7 @@ class LeanplumMetricsService(
deviceId
}
@Suppress("ComplexMethod")
override fun start() {
if (!application.settings().isMarketingTelemetryEnabled) return
@ -255,7 +256,7 @@ class LeanplumMetricsService(
"jpn" // Japanese
)
private val PREFERENCE_NAME = "LEANPLUM_PREFERENCES"
private val DEVICE_ID_KEY = "LP_DEVICE_ID"
private const val PREFERENCE_NAME = "LEANPLUM_PREFERENCES"
private const val DEVICE_ID_KEY = "LP_DEVICE_ID"
}
}

View File

@ -140,6 +140,7 @@ internal class ReleaseMetricController(
MetricServiceType.Marketing -> isMarketingDataTelemetryEnabled()
}
@Suppress("LongMethod")
private fun Fact.toEvent(): Event? = when (Pair(component, item)) {
Component.FEATURE_PROMPTS to LoginDialogFacts.Items.DISPLAY -> Event.LoginDialogPromptDisplayed
Component.FEATURE_PROMPTS to LoginDialogFacts.Items.CANCEL -> Event.LoginDialogPromptCancelled

View File

@ -23,7 +23,6 @@ import mozilla.components.concept.engine.prompt.ShareData
import mozilla.components.feature.session.SessionFeature
import mozilla.components.support.base.feature.ViewBoundFeatureWrapper
import mozilla.components.support.ktx.kotlin.isUrl
import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.NavGraphDirections
import org.mozilla.fenix.R
@ -204,14 +203,18 @@ class DefaultBrowserToolbarController(
trackToolbarItemInteraction(item)
Do exhaustive when (item) {
ToolbarMenu.Item.Back -> sessionUseCases.goBack.invoke(currentSession)
is ToolbarMenu.Item.Forward -> {
if (FeatureFlags.tabHistory && item.viewHistory) {
is ToolbarMenu.Item.Back -> {
if (item.viewHistory) {
navController.navigate(R.id.action_global_tabHistoryDialogFragment)
} else if (!item.viewHistory) {
sessionUseCases.goForward.invoke(currentSession)
} else {
// Do nothing if tab history feature flag is off and item.viewHistory is true
sessionUseCases.goBack.invoke(currentSession)
}
}
is ToolbarMenu.Item.Forward -> {
if (item.viewHistory) {
navController.navigate(R.id.action_global_tabHistoryDialogFragment)
} else {
sessionUseCases.goForward.invoke(currentSession)
}
}
is ToolbarMenu.Item.Reload -> {
@ -383,7 +386,7 @@ class DefaultBrowserToolbarController(
@Suppress("ComplexMethod")
private fun trackToolbarItemInteraction(item: ToolbarMenu.Item) {
val eventItem = when (item) {
ToolbarMenu.Item.Back -> Event.BrowserMenuItemTapped.Item.BACK
is ToolbarMenu.Item.Back -> Event.BrowserMenuItemTapped.Item.BACK
is ToolbarMenu.Item.Forward -> Event.BrowserMenuItemTapped.Item.FORWARD
is ToolbarMenu.Item.Reload -> Event.BrowserMenuItemTapped.Item.RELOAD
ToolbarMenu.Item.Stop -> Event.BrowserMenuItemTapped.Item.STOP

View File

@ -250,8 +250,10 @@ class BrowserToolbarView(
private const val TOOLBAR_ELEVATION = 16
}
@Suppress("ComplexCondition")
private fun ToolbarMenu.Item.performHapticIfNeeded(view: View) {
if (this is ToolbarMenu.Item.Reload && this.bypassCache ||
this is ToolbarMenu.Item.Back && this.viewHistory ||
this is ToolbarMenu.Item.Forward && this.viewHistory
) {
view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)

View File

@ -74,6 +74,20 @@ class DefaultToolbarMenu(
}
override val menuToolbar by lazy {
val back = BrowserMenuItemToolbar.TwoStateButton(
primaryImageResource = mozilla.components.ui.icons.R.drawable.mozac_ic_back,
primaryContentDescription = context.getString(R.string.browser_menu_back),
primaryImageTintResource = primaryTextColor(),
isInPrimaryState = {
session?.canGoBack ?: true
},
secondaryImageTintResource = ThemeManager.resolveAttribute(R.attr.disabled, context),
disableInSecondaryState = true,
longClickListener = { onItemTapped.invoke(ToolbarMenu.Item.Back(viewHistory = true)) }
) {
onItemTapped.invoke(ToolbarMenu.Item.Back(viewHistory = false))
}
val forward = BrowserMenuItemToolbar.TwoStateButton(
primaryImageResource = mozilla.components.ui.icons.R.drawable.mozac_ic_forward,
primaryContentDescription = context.getString(R.string.browser_menu_forward),
@ -135,7 +149,7 @@ class DefaultToolbarMenu(
onItemTapped.invoke(ToolbarMenu.Item.Bookmark)
}
BrowserMenuItemToolbar(listOf(bookmark, share, forward, refresh))
BrowserMenuItemToolbar(listOf(back, forward, bookmark, share, refresh))
}
// Predicates that need to be repeatedly called as the session changes

View File

@ -13,7 +13,7 @@ interface ToolbarMenu {
data class RequestDesktop(val isChecked: Boolean) : Item()
object FindInPage : Item()
object Share : Item()
object Back : Item()
data class Back(val viewHistory: Boolean) : Item()
data class Forward(val viewHistory: Boolean) : Item()
data class Reload(val bypassCache: Boolean) : Item()
object Stop : Item()

View File

@ -59,9 +59,10 @@ class CustomTabToolbarMenu(
R.attr.disabled,
context
),
disableInSecondaryState = true
disableInSecondaryState = true,
longClickListener = { onItemTapped.invoke(ToolbarMenu.Item.Back(viewHistory = true)) }
) {
onItemTapped.invoke(ToolbarMenu.Item.Back)
onItemTapped.invoke(ToolbarMenu.Item.Back(viewHistory = false))
}
val forward = BrowserMenuItemToolbar.TwoStateButton(

View File

@ -232,7 +232,10 @@ class DefaultSessionControlController(
}
override fun handleCollectionShareTabsClicked(collection: TabCollection) {
showShareFragment(collection.tabs.map { ShareData(url = it.url, title = it.title) })
showShareFragment(
collection.title,
collection.tabs.map { ShareData(url = it.url, title = it.title) }
)
metrics.track(Event.CollectionShared)
}
@ -366,8 +369,9 @@ class DefaultSessionControlController(
showTabTrayCollectionCreation()
}
private fun showShareFragment(data: List<ShareData>) {
private fun showShareFragment(shareSubject: String, data: List<ShareData>) {
val directions = HomeFragmentDirections.actionGlobalShareFragment(
shareSubject = shareSubject,
data = data.toTypedArray()
)
navController.nav(R.id.homeFragment, directions)

View File

@ -29,6 +29,7 @@ import mozilla.components.support.ktx.android.content.hasCamera
import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.Config
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.R
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.application
@ -301,7 +302,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
private fun setupPreferences() {
val leakKey = getPreferenceKey(R.string.pref_key_leakcanary)
val debuggingKey = getPreferenceKey(R.string.pref_key_remote_debugging)
val preferenceExternalDownloadManager = requirePreference<Preference>(R.string.pref_key_make_default_browser)
val preferenceLeakCanary = findPreference<Preference>(leakKey)
val preferenceRemoteDebugging = findPreference<Preference>(debuggingKey)
val preferenceMakeDefaultBrowser = requirePreference<Preference>(R.string.pref_key_make_default_browser)
@ -314,6 +315,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
}
}
preferenceExternalDownloadManager.isVisible = FeatureFlags.externalDownloadManager
preferenceRemoteDebugging?.setOnPreferenceChangeListener<Boolean> { preference, newValue ->
preference.context.settings().preferences.edit()
.putBoolean(preference.key, newValue).apply()

View File

@ -55,6 +55,7 @@ interface ShareController {
* Default behavior of [ShareController]. Other implementations are possible.
*
* @param context [Context] used for various Android interactions.
* @param shareSubject desired message subject used when sharing through 3rd party apps, like email clients.
* @param shareData the list of [ShareData]s that can be shared.
* @param sendTabUseCases instance of [SendTabUseCases] which allows sending tabs to account devices.
* @param snackbar - instance of [FenixSnackbar] for displaying styled snackbars
@ -64,6 +65,7 @@ interface ShareController {
@Suppress("TooManyFunctions")
class DefaultShareController(
private val context: Context,
private val shareSubject: String?,
private val shareData: List<ShareData>,
private val sendTabUseCases: SendTabUseCases,
private val snackbar: FenixSnackbar,
@ -90,7 +92,7 @@ class DefaultShareController(
val intent = Intent(ACTION_SEND).apply {
putExtra(EXTRA_TEXT, getShareText())
putExtra(EXTRA_SUBJECT, shareData.map { it.title }.joinToString(", "))
putExtra(EXTRA_SUBJECT, getShareSubject())
type = "text/plain"
flags = FLAG_ACTIVITY_NEW_TASK
setClassName(app.packageName, app.activityName)
@ -189,6 +191,9 @@ class DefaultShareController(
}
}
@VisibleForTesting
internal fun getShareSubject() = shareSubject ?: shareData.map { it.title }.joinToString(", ")
// Navigation between app fragments uses ShareTab as arguments. SendTabUseCases uses TabData.
@VisibleForTesting
internal fun List<ShareData>.toTabData() = map { data ->

View File

@ -67,6 +67,7 @@ class ShareFragment : AppCompatDialogFragment() {
shareInteractor = ShareInteractor(
DefaultShareController(
context = requireContext(),
shareSubject = args.shareSubject,
shareData = shareData,
snackbar = FenixSnackbar.make(
view = requireActivity().getRootView()!!,

View File

@ -34,18 +34,25 @@ class TabHistoryView(
private val adapter = TabHistoryAdapter(interactor)
private val layoutManager = object : LinearLayoutManager(containerView.context) {
private var shouldScrollToSelected = true
override fun onLayoutCompleted(state: RecyclerView.State?) {
super.onLayoutCompleted(state)
currentIndex?.let { index ->
// Force expansion of the dialog, otherwise scrolling to the current history item
// won't work when its position is near the bottom of the recyclerview.
expandDialog.invoke()
// Also, attempt to center the current history item.
val itemView = tabHistoryRecyclerView.findViewHolderForLayoutPosition(
findFirstCompletelyVisibleItemPosition()
)?.itemView
val offset = tabHistoryRecyclerView.height / 2 - (itemView?.height ?: 0) / 2
scrollToPositionWithOffset(index, offset)
// Attempt to center the current history item after the first layout is completed,
// but not after subsequent layouts
if (shouldScrollToSelected) {
// Force expansion of the dialog, otherwise scrolling to the current history item
// won't work when its position is near the bottom of the recyclerview.
expandDialog.invoke()
val itemView = tabHistoryRecyclerView.findViewHolderForLayoutPosition(
findFirstCompletelyVisibleItemPosition()
)?.itemView
val offset = tabHistoryRecyclerView.height / 2 - (itemView?.height ?: 0) / 2
scrollToPositionWithOffset(index, offset)
shouldScrollToSelected = false
}
}
}
}.apply {

View File

@ -33,7 +33,9 @@ class TabHistoryViewHolder(
history_layout.loadFavicon(item.url)
if (item.isSelected) {
history_layout.setBackgroundColor(history_layout.context.getColorFromAttr(R.attr.tabHistoryItemSelectedBackground))
history_layout.setBackgroundColor(
history_layout.context.getColorFromAttr(R.attr.tabHistoryItemSelectedBackground)
)
} else {
history_layout.background = null
}

View File

@ -8,7 +8,11 @@ import mozilla.components.support.ktx.android.content.PreferencesHolder
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
fun featureFlagPreference(key: String, default: Boolean, featureFlag: Boolean): ReadWriteProperty<PreferencesHolder, Boolean> =
fun featureFlagPreference(
key: String,
default: Boolean,
featureFlag: Boolean
): ReadWriteProperty<PreferencesHolder, Boolean> =
FeatureFlagPreferencePreference(key, default, featureFlag)
private class FeatureFlagPreferencePreference(

View File

@ -340,7 +340,7 @@ class Settings(private val appContext: Context) : PreferencesHolder {
* Caches the last known "is default browser" state when the app was paused.
* For an up to do date state use `isDefaultBrowser` instead.
*/
var wasDefaultBrowserOnLastPause by booleanPreference(
var wasDefaultBrowserOnLastResume by booleanPreference(
appContext.getPreferenceKey(R.string.pref_key_default_browser),
default = isDefaultBrowser()
)

View File

@ -53,7 +53,8 @@
app:layout_constraintStart_toEndOf="@id/icon"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/url"
app:layout_constraintVertical_chainStyle="packed"/>
app:layout_constraintVertical_chainStyle="packed"
app:layout_goneMarginEnd="@dimen/library_item_icon_margin_horizontal" />
<TextView
android:id="@+id/url"
@ -69,7 +70,8 @@
app:layout_constraintEnd_toStartOf="@id/overflow_menu"
app:layout_constraintStart_toEndOf="@id/icon"
app:layout_constraintTop_toBottomOf="@+id/title"
app:layout_constraintBottom_toBottomOf="parent" />
app:layout_constraintBottom_toBottomOf="parent"
app:layout_goneMarginEnd="@dimen/library_item_icon_margin_horizontal" />
<ImageButton
android:id="@+id/overflow_menu"

View File

@ -677,6 +677,11 @@
android:defaultValue="null"
app:argType="string"
app:nullable="true" />
<argument
android:name="shareSubject"
android:defaultValue="@null"
app:argType="string"
app:nullable="true" />
</dialog>
<dialog
android:id="@+id/quickSettingsSheetDialogFragment"

View File

@ -2,7 +2,7 @@
<resources>
<!-- App name for private browsing mode. The first parameter is the name of the app defined in app_name (for example: Fenix)-->
<string name="app_name_private_5">Privado %s</string>
<string name="app_name_private_5">%s privado</string>
<!-- App name for private browsing mode. The first parameter is the name of the app defined in app_name (for example: Fenix)-->
<string name="app_name_private_4">%s (Privado)</string>
<!-- Home Fragment -->

View File

@ -27,6 +27,9 @@
<!-- Message announced to the user when tab tray is selected with 0 or 2+ tabs -->
<string name="open_tab_tray_plural">%1$s pestañas abiertas. Tocar para cambiar de pestaña.</string>
<!-- Content description for checkmark while tab is selected while in multiselect mode in tab tray. The first parameter is the title of the tab selected -->
<string name="tab_tray_item_selected_multiselect_content_description">%1$s seleccionado</string>
<!-- About content. The first parameter is the name of the application. (For example: Fenix) -->
<string name="about_content">%1$s es producido por Mozilla.</string>

View File

@ -40,6 +40,8 @@
<string name="tab_tray_collection_button_multiselect_content_description">Tallenna valitut välilehdet kokoelmaan</string>
<!-- Content description for checkmark while tab is selected while in multiselect mode in tab tray. The first parameter is the title of the tab selected -->
<string name="tab_tray_item_selected_multiselect_content_description">Valittu %1$s</string>
<!-- Content description when tab is unselected while in multiselect mode in tab tray. The first parameter is the title of the tab unselected -->
<string name="tab_tray_item_unselected_multiselect_content_description">Kumottu valinta %1$s</string>
<!-- Content description announcement when exiting multiselect mode in tab tray -->
<string name="tab_tray_exit_multiselect_content_description">Poistuttiin monivalintatilasta</string>
<!-- Content description announcement when entering multiselect mode in tab tray -->

View File

@ -37,9 +37,18 @@
<string name="tab_tray_close_multiselect_content_description">मल्टीसेलेक्ट मोड से बाहर निकलें</string>
<!-- Content description for save to collection button while in multiselect mode in tab tray -->
<string name="tab_tray_collection_button_multiselect_content_description">चुने गए टैब को संग्रह में सहेजें</string>
<!-- Content description for checkmark while tab is selected while in multiselect mode in tab tray. The first parameter is the title of the tab selected -->
<string name="tab_tray_item_selected_multiselect_content_description">%1$s चयनित</string>
<!-- Content description when tab is unselected while in multiselect mode in tab tray. The first parameter is the title of the tab unselected -->
<string name="tab_tray_item_unselected_multiselect_content_description">%1$s अचयनित</string>
<!-- Content description announcement when exiting multiselect mode in tab tray -->
<string name="tab_tray_exit_multiselect_content_description">मल्टीसेलेक्ट मोड से बाहर निकल चुके</string>
<!-- Content description announcement when entering multiselect mode in tab tray -->
<string name="tab_tray_enter_multiselect_content_description">मल्टीसेलेक्ट मोड में दाखिल, संग्रह में सहेजने के लिए टैबों को चुनें</string>
<!-- Content description on checkmark while tab is selected in multiselect mode in tab tray -->
<string name="tab_tray_multiselect_selected_content_description">चयनित</string>
<!-- About content. The first parameter is the name of the application. (For example: Fenix) -->
<string name="about_content">%1$s को Mozilla द्वारा निर्मित किया गया है।</string>
@ -165,8 +174,8 @@
<!-- Search Fragment -->
<!-- Button in the search view that lets a user search by scanning a QR code -->
<string name="search_scan_button">स्कैन करें</string>
<!-- Button in the search view that lets a user search by using a shortcut -->
<string name="search_engines_shortcut_button">खोज इंजन</string>
<!-- Button in the search view that lets a user change their search engine -->
<string name="search_engine_button">खोज इंजन</string>
<!-- Button in the search view when shortcuts are displayed that takes a user to the search engine settings -->
<string name="search_shortcuts_engine_settings">खोज इंजन सेटिंग्स</string>
<!-- Header displayed when selecting a shortcut search engine -->
@ -597,6 +606,8 @@
<string name="bookmark_select_folder">फ़ोल्डर चुनें</string>
<!-- Confirmation message for a dialog confirming if the user wants to delete the selected folder -->
<string name="bookmark_delete_folder_confirmation_dialog">क्या आप वाकई इस फ़ोल्डर को हटाना चाहते हैं?</string>
<!-- Confirmation message for a dialog confirming if the user wants to delete multiple items including folders. Parameter will be replaced by app name. -->
<string name="bookmark_delete_multiple_folders_confirmation_dialog">%s चयनित वस्तुओं को मिटा देगा।</string>
<!-- Snackbar title shown after a folder has been deleted. This first parameter is the name of the deleted folder -->
<string name="bookmark_delete_folder_snackbar">%1$s मिटाया गया</string>
<!-- Screen title for adding a bookmarks folder -->
@ -655,6 +666,8 @@
<!-- Bookmark snackbar message on deleting multiple bookmarks not including folders-->
<string name="bookmark_deletion_multiple_snackbar_message_2">बुकमार्क मिटा दिए गए</string>
<!-- Bookmark snackbar message on deleting multiple bookmarks including folders-->
<string name="bookmark_deletion_multiple_snackbar_message_3">चयनित फोल्डर मिटाए जा रहे हैं</string>
<!-- Bookmark undo button for deletion snackbar action -->
<string name="bookmark_undo_deletion">पूर्ववत करें</string>
@ -860,6 +873,8 @@
<string name="tab_collection_dialog_message">क्या आप वाकई %1$s को हटाना चाहते हैं?</string>
<!-- Collection and tab deletion prompt dialog message. This will show when the last tab from a collection is deleted -->
<string name="delete_tab_and_collection_dialog_message">इस टैब को हटाने से संपूर्ण संग्रह मिट जाएगा। आप किसी भी समय नए संग्रह बना सकते हैं।</string>
<!-- Collection and tab deletion prompt dialog title. Placeholder will be replaced with the collection name. This will show when the last tab from a collection is deleted -->
<string name="delete_tab_and_collection_dialog_title">%1$s को मिटाएं?</string>
<!-- Tab collection deletion prompt dialog option to delete the collection -->
<string name="tab_collection_dialog_positive">मिटाएं</string>
<!-- Tab collection deletion prompt dialog option to cancel deleting the collection -->
@ -1269,6 +1284,8 @@
<string name="preferences_passwords_exceptions_description_empty">लॉगिन और पासवर्ड जो सहेजे नहीं गए हैं उन्हें यहां दिखाये जायेंगे।</string>
<!-- Description of list of login exceptions that we never save logins for -->
<string name="preferences_passwords_exceptions_description">इन साइटों के लिए लॉगिन और पासवर्ड सहेजे नहीं जाएंगे।</string>
<!-- Text on button to remove all saved login exceptions -->
<string name="preferences_passwords_exceptions_remove_all">सभी अपवादों को मिटाएं</string>
<!-- Hint for search box in logins list -->
<string name="preferences_passwords_saved_logins_search">लॉगिन खोजें</string>
<!-- Option to sort logins list A-Z, alphabetically -->
@ -1472,9 +1489,7 @@
<string name="saved_login_duplicate">एक लॉगिन इस उपयोगकर्ता नाम के साथ मौजूद है</string>
<!-- Synced Tabs -->
<!-- Text displayed when user is not logged into a Firefox Account -->
<string name="synced_tabs_connect_to_sync_account">Firefox खाते से कनेक्ट करें।</string>
<!-- Text displayed to ask user to connect another device as no devices found with account -->
<!-- Text displayed to ask user to connect another device as no devices found with account -->
<string name="synced_tabs_connect_another_device">अन्य डिवाइस कनेक्ट करें</string>
<!-- Text displayed asking user to re-authenticate -->
<string name="synced_tabs_reauth">कृपया पुनः प्रमाणित करें।</string>
@ -1495,13 +1510,4 @@
<!-- Confirmation dialog button text when top sites limit is reached. -->
<string name="top_sites_max_limit_confirmation_button">ठीक है, समझ गए</string>
<!-- DEPRECATED STRINGS -->
<!-- Button in the search view that lets a user search by using a shortcut -->
<string name="search_shortcuts_button">शॉर्टकट</string>
<!-- DEPRECATED: Header displayed when selecting a shortcut search engine -->
<string name="search_shortcuts_search_with">के साथ खोजें</string>
<!-- Header displayed when selecting a shortcut search engine -->
<string name="search_shortcuts_search_with_2">इस बार, इसके साथ खोजें:</string>
<!-- Preference title for switch preference to show search shortcuts -->
<string name="preferences_show_search_shortcuts">खोज शॉर्टकट्स दिखाएं</string>
</resources>

View File

@ -734,7 +734,7 @@
<!-- Content description (not visible, for screen readers etc.): Opens the collection menu when pressed -->
<string name="collection_menu_button_content_description">Gyűjtemény menü</string>
<!-- No Open Tabs Message Header -->
<string name="no_collections_header1">Gyűjtsd össze a számára fontos dolgokat</string>
<string name="no_collections_header1">Gyűjtse össze az Önnek fontos dolgokat</string>
<!-- Label to describe what collections are to a new user without any collections -->
<string name="no_collections_description1">Csoportosítsa a hasonló kereséseket, webhelyeket és lapokat a későbbi gyors elérés érdekében.</string>
<!-- Title for the "select tabs" step of the collection creator -->

View File

@ -27,6 +27,29 @@
<!-- Message announced to the user when tab tray is selected with 0 or 2+ tabs -->
<string name="open_tab_tray_plural">%1$s tab terbuka. Ketuk untuk beralih tab.</string>
<!-- Tab tray multi select title in app bar. The first parameter is the number of tabs selected -->
<string name="tab_tray_multi_select_title">%1$d terpilih</string>
<!-- Label of button in create collection dialog for creating a new collection -->
<string name="tab_tray_add_new_collection">Tambah koleksi baru</string>
<!-- Label of editable text in create collection dialog for naming a new collection -->
<string name="tab_tray_add_new_collection_name">Nama</string>
<!-- Label of button in save to collection dialog for selecting a current collection -->
<string name="tab_tray_select_collection">Pilih koleksi</string>
<!-- Content description for close button while in multiselect mode in tab tray -->
<string name="tab_tray_close_multiselect_content_description">Keluar mode seleksi ganda</string>
<!-- Content description for save to collection button while in multiselect mode in tab tray -->
<string name="tab_tray_collection_button_multiselect_content_description">Simpan tab terpilih ke koleksi</string>
<!-- Content description for checkmark while tab is selected while in multiselect mode in tab tray. The first parameter is the title of the tab selected -->
<string name="tab_tray_item_selected_multiselect_content_description">%1$s dipilih</string>
<!-- Content description when tab is unselected while in multiselect mode in tab tray. The first parameter is the title of the tab unselected -->
<string name="tab_tray_item_unselected_multiselect_content_description">%1$s tidak dipilih</string>
<!-- Content description announcement when exiting multiselect mode in tab tray -->
<string name="tab_tray_exit_multiselect_content_description">Keluar dari mode seleksi ganda</string>
<!-- Content description announcement when entering multiselect mode in tab tray -->
<string name="tab_tray_enter_multiselect_content_description">Memasuki mode seleksi ganda, pilih tab untuk menyimpannya ke koleksi</string>
<!-- Content description on checkmark while tab is selected in multiselect mode in tab tray -->
<string name="tab_tray_multiselect_selected_content_description">Terpilih</string>
<!-- About content. The first parameter is the name of the application. (For example: Fenix) -->
<string name="about_content">%1$s diproduksi oleh Mozilla.</string>
@ -152,15 +175,13 @@
<!-- Search Fragment -->
<!-- Button in the search view that lets a user search by scanning a QR code -->
<string name="search_scan_button">Pindai</string>
<!-- Button in the search view that lets a user search by using a shortcut -->
<string name="search_shortcuts_button">Pintasan</string>
<!-- Button in the search view that lets a user change their search engine -->
<string name="search_engine_button">Mesin pencari</string>
<!-- Button in the search view when shortcuts are displayed that takes a user to the search engine settings -->
<string name="search_shortcuts_engine_settings">Setelan mesin pencari</string>
<!-- DEPRECATED: Header displayed when selecting a shortcut search engine -->
<string name="search_shortcuts_search_with">Cari dengan</string>
<!-- Header displayed when selecting a shortcut search engine -->
<string name="search_shortcuts_search_with_2">Kali ini, cari lewat:</string>
<string name="search_engines_search_with">Saat ini, cari dengan:</string>
<!-- Button in the search view that lets a user navigate to the site in their clipboard -->
<string name="awesomebar_clipboard_title">Isi tautan dari papan klip</string>
@ -270,8 +291,8 @@
<string name="developer_tools_category">Perangkat pengembang</string>
<!-- Preference for developers -->
<string name="preferences_remote_debugging">Pengawakutuan jarak jauh melalui USB</string>
<!-- Preference title for switch preference to show search shortcuts -->
<string name="preferences_show_search_shortcuts">Tampilkan pintasan pencarian</string>
<!-- Preference title for switch preference to show search engines -->
<string name="preferences_show_search_engines">Tampilkan mesin pencari</string>
<!-- Preference title for switch preference to show search suggestions -->
<string name="preferences_show_search_suggestions">Tampilkan saran pencarian</string>
<!-- Preference title for switch preference to show voice search button -->
@ -525,6 +546,9 @@
<!-- Postfix for private WebApp titles, placeholder is replaced with app name -->
<string name="pwa_site_controls_title_private">%1$s (Mode Privat)</string>
<!-- Button in the current tab tray header in multiselect mode. Saved the selected tabs to a collection when pressed. -->
<string name="tab_tray_save_to_collection">Simpan</string>
<!-- History -->
<!-- Text for the button to clear all history -->
<string name="history_delete_all">Hapus riwayat</string>
@ -592,6 +616,8 @@
<string name="bookmark_select_folder">Pilih folder</string>
<!-- Confirmation message for a dialog confirming if the user wants to delete the selected folder -->
<string name="bookmark_delete_folder_confirmation_dialog">Yakin akan menghapus folder ini?</string>
<!-- Confirmation message for a dialog confirming if the user wants to delete multiple items including folders. Parameter will be replaced by app name. -->
<string name="bookmark_delete_multiple_folders_confirmation_dialog">%s akan menghapus item terpilih.</string>
<!-- Snackbar title shown after a folder has been deleted. This first parameter is the name of the deleted folder -->
<string name="bookmark_delete_folder_snackbar">%1$s terhapus</string>
<!-- Screen title for adding a bookmarks folder -->
@ -646,8 +672,10 @@
<!-- Bookmark snackbar message on deletion
The first parameter is the host part of the URL of the bookmark deleted, if any -->
<string name="bookmark_deletion_snackbar_message">%1$s terhapus</string>
<!-- Bookmark snackbar message on deleting multiple bookmarks -->
<!-- Bookmark snackbar message on deleting multiple bookmarks not including folders-->
<string name="bookmark_deletion_multiple_snackbar_message_2">Markah dihapus</string>
<!-- Bookmark snackbar message on deleting multiple bookmarks including folders-->
<string name="bookmark_deletion_multiple_snackbar_message_3">Menghapus folder terpilih</string>
<!-- Bookmark undo button for deletion snackbar action -->
<string name="bookmark_undo_deletion">URUNGKAN</string>
@ -743,6 +771,8 @@
<string name="create_collection_save_to_collection_tab_selected">%d tab dipilih</string>
<!-- Text shown in snackbar when multiple tabs have been saved in a collection -->
<string name="create_collection_tabs_saved">Tab disimpan!</string>
<!-- Text shown in snackbar when one or multiple tabs have been saved in a new collection -->
<string name="create_collection_tabs_saved_new_collection">Koleksi disimpan!</string>
<!-- Text shown in snackbar when one tab has been saved in a collection -->
<string name="create_collection_tab_saved">Tab disimpan!</string>
<!-- Content description (not visible, for screen readers etc.): button to close the collection creator -->
@ -849,6 +879,10 @@
<string name="qr_scanner_dialog_negative">TOLAK</string>
<!-- Tab collection deletion prompt dialog message. Placeholder will be replaced with the collection name -->
<string name="tab_collection_dialog_message">Yakin ingin menghapus %1$s?</string>
<!-- Collection and tab deletion prompt dialog message. This will show when the last tab from a collection is deleted -->
<string name="delete_tab_and_collection_dialog_message">Menghapus tab ini akan menghapus keseluruhan koleksi. Kamu dapat membuat koleksi baru kapan saja.</string>
<!-- Collection and tab deletion prompt dialog title. Placeholder will be replaced with the collection name. This will show when the last tab from a collection is deleted -->
<string name="delete_tab_and_collection_dialog_title">Hapus %1$s?</string>
<!-- Tab collection deletion prompt dialog option to delete the collection -->
<string name="tab_collection_dialog_positive">Hapus</string>
<!-- Tab collection deletion prompt dialog option to cancel deleting the collection -->
@ -1249,6 +1283,8 @@
<string name="preferences_passwords_exceptions_description_empty">Info masuk dan kata sandi yang tidak disimpan akan ditampilkan di sini.</string>
<!-- Description of list of login exceptions that we never save logins for -->
<string name="preferences_passwords_exceptions_description">Info masuk dan kata sandi tidak akan disimpan untuk situs-situs ini.</string>
<!-- Text on button to remove all saved login exceptions -->
<string name="preferences_passwords_exceptions_remove_all">Hapus semua pengecualian</string>
<!-- Hint for search box in logins list -->
<string name="preferences_passwords_saved_logins_search">Cari log masuk</string>
<!-- Option to sort logins list A-Z, alphabetically -->
@ -1287,6 +1323,8 @@
<string name="saved_login_copy_username">Salin nama pengguna</string>
<!-- Content Description (for screenreaders etc) read for the button to copy a site in logins -->
<string name="saved_login_copy_site">Salin situs</string>
<!-- Content Description (for screenreaders etc) read for the button to open a site in logins -->
<string name="saved_login_open_site">Buka situs di peramban</string>
<!-- Content Description (for screenreaders etc) read for the button to reveal a password in logins -->
<string name="saved_login_reveal_password">Tampilkan sandi</string>
<!-- Content Description (for screenreaders etc) read for the button to hide a password in logins -->
@ -1437,9 +1475,7 @@
<string name="saved_login_duplicate">Sebuah info masuk dengan nama pengguna tersebut sudah ada</string>
<!-- Synced Tabs -->
<!-- Text displayed when user is not logged into a Firefox Account -->
<string name="synced_tabs_connect_to_sync_account">Hubungkan dengan Firefox Account.</string>
<!-- Text displayed to ask user to connect another device as no devices found with account -->
<!-- Text displayed to ask user to connect another device as no devices found with account -->
<string name="synced_tabs_connect_another_device">Hubungkan perangkat lain</string>
<!-- Text displayed asking user to re-authenticate -->
<string name="synced_tabs_reauth">Harap autentikasi ulang.</string>

File diff suppressed because one or more lines are too long

View File

@ -33,12 +33,16 @@
<string name="tab_tray_add_new_collection_name">Nom</string>
<!-- Label of button in save to collection dialog for selecting a current collection -->
<string name="tab_tray_select_collection">Seleccionar una colleccion</string>
<!-- Content description for close button while in multiselect mode in tab tray -->
<string name="tab_tray_close_multiselect_content_description">Sortir del mòde seleccion multipla</string>
<!-- Content description for save to collection button while in multiselect mode in tab tray -->
<string name="tab_tray_collection_button_multiselect_content_description">Enregistrar los onglets seleccionats dins la colleccion</string>
<!-- Content description for checkmark while tab is selected while in multiselect mode in tab tray. The first parameter is the title of the tab selected -->
<string name="tab_tray_item_selected_multiselect_content_description">%1$s seleccionat</string>
<!-- Content description when tab is unselected while in multiselect mode in tab tray. The first parameter is the title of the tab unselected -->
<string name="tab_tray_item_unselected_multiselect_content_description">%1$s deseleccionat</string>
<!-- Content description announcement when exiting multiselect mode in tab tray -->
<string name="tab_tray_exit_multiselect_content_description">Sortida del mòde seleccion multipla</string>
<!-- Content description on checkmark while tab is selected in multiselect mode in tab tray -->
<string name="tab_tray_multiselect_selected_content_description">Seleccionat</string>
@ -912,6 +916,8 @@
<!-- Dialog message to the user asking to delete browsing data. -->
<string name="delete_browsing_data_prompt_message">Aquò suprimirà totas las donadas de navegacion.</string>
<!-- Dialog message to the user asking to delete browsing data. Parameter will be replaced by app name. -->
<string name="delete_browsing_data_prompt_message_3">%s suprimirà las donadas de navegacion seleccionadas.</string>
<!-- Text for the cancel button for the data deletion dialog -->
<string name="delete_browsing_data_prompt_cancel">Anullar</string>
@ -1123,6 +1129,10 @@
<!-- About page link text to open what's new link -->
<string name="about_whats_new">Ques nòu dins %s</string>
<!-- Open source licenses page title
The first parameter is the app name -->
<string name="open_source_licenses_title">%s | Bibliotècas liuras</string>
<!-- About page link text to open support link -->
<string name="about_support">Assisténcia</string>
@ -1192,6 +1202,10 @@
<string name="preferences_passwords_saved_logins_description_empty_learn_more_link">Per ne saber mai sus Sync.</string>
<!-- Preference to access list of login exceptions that we never save logins for -->
<string name="preferences_passwords_exceptions">Excepcions</string>
<!-- Empty description of list of login exceptions that we never save logins for -->
<string name="preferences_passwords_exceptions_description_empty">Los identificants e senhals pas salvats seràn mostrats aquí.</string>
<!-- Description of list of login exceptions that we never save logins for -->
<string name="preferences_passwords_exceptions_description">Los identificants e senhals seràn pas salvats per aquestes sites.</string>
<!-- Text on button to remove all saved login exceptions -->
<string name="preferences_passwords_exceptions_remove_all">Suprimir totas las excepcions</string>
<!-- Hint for search box in logins list -->
@ -1245,6 +1259,8 @@
<string name="logins_warning_dialog_set_up_now">O configurar ara</string>
<!-- Title of PIN verification dialog to direct users to re-enter their device credentials to access their logins -->
<string name="logins_biometric_prompt_message_pin">Desverrolhatz lo periferic</string>
<!-- Title for Accessibility Force Enable Zoom Preference -->
<string name="preference_accessibility_force_enable_zoom">Zoom per totes los sites</string>
<!-- Saved logins sorting strategy menu item -by name- (if selected, it will sort saved logins alphabetically) -->
<string name="saved_logins_sort_strategy_alphabetically">Nom (A-Z)</string>
<!-- Saved logins sorting strategy menu item -by last used- (if selected, it will sort saved logins by last used) -->
@ -1274,6 +1290,8 @@
<!-- Text for the button to learn more about adding a custom search engine -->
<string name="search_add_custom_engine_learn_more_label">Ne saber mai</string>
<!-- Accessibility description for the form in which details about the custom search engine are entered -->
<string name="search_add_custom_engine_form_description">Detalhs del motor de recèrca personalizat</string>
<!-- Accessibility description for the 'Learn more' link -->
<string name="search_add_custom_engine_learn_more_description">Ligam per ne saber mai</string>
@ -1360,6 +1378,9 @@
<!-- Voice search prompt description displayed after the user presses the voice search button -->
<string name="voice_search_explainer">Parlatz ara</string>
<!-- The error message in edit login view when a duplicate username exists. -->
<string name="saved_login_duplicate">Un identificant amb aqueste nom dutilizaire existís ja</string>
<!-- Synced Tabs -->
<!-- Text displayed to ask user to connect another device as no devices found with account -->
<string name="synced_tabs_connect_another_device">Connectatz un autre periferic.</string>

View File

@ -25,6 +25,8 @@
<!-- Message announced to the user when tab tray is selected with 0 or 2+ tabs -->
<string name="open_tab_tray_plural">Odprtih zavihkov: %1$s. Tapnite za preklop zavihkov.</string>
<!-- Tab tray multi select title in app bar. The first parameter is the number of tabs selected -->
<string name="tab_tray_multi_select_title">%1$d izbranih</string>
<!-- Label of button in create collection dialog for creating a new collection -->
<string name="tab_tray_add_new_collection">Dodaj novo zbirko</string>
<!-- Label of editable text in create collection dialog for naming a new collection -->

View File

@ -149,6 +149,7 @@
<!-- Privacy Settings -->
<string name="pref_key_open_links_in_a_private_tab" translatable="false">pref_key_open_links_in_a_private_tab</string>
<string name="pref_key_open_links_in_external_app" translatable="false">pref_key_open_links_in_external_app</string>
<string name="pref_key_external_download_manager" translatable="false">pref_key_external_download_manager</string>
<string name="pref_key_allow_screenshots_in_private_mode" translatable="false">pref_key_allow_screenshots_in_private_mode</string>
<!-- Quick Action Sheet -->

View File

@ -296,6 +296,8 @@
<string name="preferences_account_settings">Account settings</string>
<!-- Preference for open links in third party apps -->
<string name="preferences_open_links_in_apps">Open links in apps</string>
<!-- Preference for open download with an external download manager app -->
<string name="preferences_external_download_manager">External download manager</string>
<!-- Preference for add_ons -->
<string name="preferences_addons">Add-ons</string>

View File

@ -132,6 +132,12 @@
android:key="@string/pref_key_open_links_in_external_app"
android:title="@string/preferences_open_links_in_apps" />
<androidx.preference.SwitchPreference
android:defaultValue="false"
android:icon="@drawable/ic_download"
android:key="@string/pref_key_external_download_manager"
android:title="@string/preferences_external_download_manager" />
<androidx.preference.SwitchPreference
android:defaultValue="true"
android:icon="@drawable/ic_info"

View File

@ -217,7 +217,7 @@ class DefaultBrowserToolbarControllerTest {
@Test
fun handleToolbarBackPress() = runBlockingTest {
val item = ToolbarMenu.Item.Back
val item = ToolbarMenu.Item.Back(false)
val controller = createController(scope = this)
controller.handleToolbarItemInteraction(item)
@ -226,6 +226,17 @@ class DefaultBrowserToolbarControllerTest {
verify { sessionUseCases.goBack(currentSession) }
}
@Test
fun handleToolbarBackLongPress() = runBlockingTest {
val item = ToolbarMenu.Item.Back(true)
val controller = createController(scope = this)
controller.handleToolbarItemInteraction(item)
verify { metrics.track(Event.BrowserMenuItemTapped(Event.BrowserMenuItemTapped.Item.BACK)) }
verify { navController.navigate(R.id.action_global_tabHistoryDialogFragment) }
}
@Test
fun handleToolbarForwardPress() = runBlockingTest {
val item = ToolbarMenu.Item.Forward(false)

View File

@ -212,6 +212,7 @@ class DefaultSessionControlControllerTest {
fun handleCollectionShareTabsClicked() {
val collection = mockk<TabCollection> {
every { tabs } returns emptyList()
every { title } returns ""
}
controller.handleCollectionShareTabsClicked(collection)

View File

@ -48,6 +48,7 @@ class ShareControllerTest {
// Need a valid context to retrieve Strings for example, but we also need it to return our "metrics"
private val context: Context = spyk(testContext)
private val metrics: MetricController = mockk(relaxed = true)
private val shareSubject = "shareSubject"
private val shareData = listOf(
ShareData(url = "url0", title = "title0"),
ShareData(url = "url1", title = "title1")
@ -65,7 +66,7 @@ class ShareControllerTest {
private val dismiss = mockk<(ShareController.Result) -> Unit>(relaxed = true)
private val recentAppStorage = mockk<RecentAppsStorage>(relaxed = true)
private val controller = DefaultShareController(
context, shareData, sendTabUseCases, snackbar, navController,
context, shareSubject, shareData, sendTabUseCases, snackbar, navController,
recentAppStorage, testCoroutineScope, dismiss
)
@ -91,8 +92,8 @@ class ShareControllerTest {
// needed for capturing the actual Intent used the `slot` one doesn't have this flag so we
// need to use an Activity Context.
val activityContext: Context = mockk<Activity>()
val testController = DefaultShareController(activityContext, shareData, mockk(), mockk(), mockk(),
recentAppStorage, testCoroutineScope, dismiss)
val testController = DefaultShareController(activityContext, shareSubject, shareData, mockk(),
mockk(), mockk(), recentAppStorage, testCoroutineScope, dismiss)
every { activityContext.startActivity(capture(shareIntent)) } just Runs
every { recentAppStorage.updateRecentApp(appShareOption.activityName) } just Runs
@ -101,6 +102,7 @@ class ShareControllerTest {
// Check that the Intent used for querying apps has the expected structure
assertTrue(shareIntent.isCaptured)
assertEquals(Intent.ACTION_SEND, shareIntent.captured.action)
assertEquals(shareSubject, shareIntent.captured.extras!![Intent.EXTRA_SUBJECT])
assertEquals(textToShare, shareIntent.captured.extras!![Intent.EXTRA_TEXT])
assertEquals("text/plain", shareIntent.captured.type)
assertEquals(Intent.FLAG_ACTIVITY_NEW_TASK, shareIntent.captured.flags)
@ -124,8 +126,8 @@ class ShareControllerTest {
// needed for capturing the actual Intent used the `slot` one doesn't have this flag so we
// need to use an Activity Context.
val activityContext: Context = mockk<Activity>()
val testController = DefaultShareController(activityContext, shareData, mockk(), snackbar,
mockk(), mockk(), testCoroutineScope, dismiss)
val testController = DefaultShareController(activityContext, shareSubject, shareData, mockk(),
snackbar, mockk(), mockk(), testCoroutineScope, dismiss)
every { activityContext.startActivity(capture(shareIntent)) } throws SecurityException()
every { activityContext.getString(R.string.share_error_snackbar) } returns "Cannot share to this app"
@ -247,6 +249,7 @@ class ShareControllerTest {
fun `getSuccessMessage should return different strings depending on the number of shared tabs`() {
val controllerWithOneSharedTab = DefaultShareController(
context,
shareSubject,
listOf(ShareData(url = "url0", title = "title0")),
mockk(),
mockk(),
@ -280,7 +283,7 @@ class ShareControllerTest {
ShareData(url = "url1")
)
val controller = DefaultShareController(
context, shareData, sendTabUseCases, snackbar, navController,
context, shareSubject, shareData, sendTabUseCases, snackbar, navController,
recentAppStorage, testCoroutineScope, dismiss
)
@ -288,6 +291,21 @@ class ShareControllerTest {
assertEquals(expectedShareText, controller.getShareText())
}
@Test
fun `getShareSubject will return "shareSubject" if that is non null`() {
assertEquals(shareSubject, controller.getShareSubject())
}
@Test
fun `getShareSubject will return a concatenation of tab titles if "shareSubject" is null`() {
val controller = DefaultShareController(
context, null, shareData, sendTabUseCases, snackbar, navController,
recentAppStorage, testCoroutineScope, dismiss
)
assertEquals("title0, title1", controller.getShareSubject())
}
@Test
fun `ShareTab#toTabData maps a list of ShareTab to a TabData list`() {
var tabData: List<TabData>

View File

@ -76,7 +76,7 @@ complexity:
# https://github.com/mozilla-mobile/fenix/issues/4861
threshold: 75
LongParameterList:
active: trued
active: true
excludes: "**/*Controller.kt, **/*Integration.kt"
functionThreshold: 6
constructorThreshold: 7