Copione merged onto master
continuous-integration/drone/push Build is failing
Details
continuous-integration/drone/push Build is failing
Details
commit
d518f35c3e
|
@ -67,7 +67,9 @@ Before you attempt to make a contribution please read the [Community Participati
|
||||||
|
|
||||||
## Build Instructions
|
## Build Instructions
|
||||||
|
|
||||||
Note: Both Android SDK and NDK are required.
|
Pre-requisites:
|
||||||
|
* Android SDK
|
||||||
|
* To run command line tools, you'll need to configure Java: see [our how-to guide](https://github.com/mozilla-mobile/shared-docs/blob/master/android/configure_java.md).
|
||||||
|
|
||||||
1. Clone or Download the repository:
|
1. Clone or Download the repository:
|
||||||
|
|
||||||
|
@ -131,6 +133,9 @@ recommend you use our provided pre-push hook in `config/pre-push-recommended.sh`
|
||||||
Using this hook will guarantee your hook gets updated as the repository changes.
|
Using this hook will guarantee your hook gets updated as the repository changes.
|
||||||
This hook tries to run as much as possible without taking too much time.
|
This hook tries to run as much as possible without taking too much time.
|
||||||
|
|
||||||
|
Before you can run the hook, you'll need to configure Java properly because it relies on command line tools: see
|
||||||
|
[our how-to guide](https://github.com/mozilla-mobile/shared-docs/blob/master/android/configure_java.md).
|
||||||
|
|
||||||
To add it on Mac/Linux, run this command from the project root:
|
To add it on Mac/Linux, run this command from the project root:
|
||||||
```sh
|
```sh
|
||||||
ln -s ../../config/pre-push-recommended.sh .git/hooks/pre-push
|
ln -s ../../config/pre-push-recommended.sh .git/hooks/pre-push
|
||||||
|
|
|
@ -72,20 +72,6 @@ android {
|
||||||
"sharedUserId": "org.mozilla.fenix.performancetest.sharedID"
|
"sharedUserId": "org.mozilla.fenix.performancetest.sharedID"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
fenixNightly releaseTemplate >> {
|
|
||||||
applicationIdSuffix ".fenix.nightly"
|
|
||||||
buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
|
|
||||||
def deepLinkSchemeValue = "fenix-nightly"
|
|
||||||
buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
|
|
||||||
manifestPlaceholders = ["deepLinkScheme": deepLinkSchemeValue]
|
|
||||||
}
|
|
||||||
fenixBeta releaseTemplate >> {
|
|
||||||
applicationIdSuffix ".fenix.beta"
|
|
||||||
buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
|
|
||||||
def deepLinkSchemeValue = "fenix-beta"
|
|
||||||
buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
|
|
||||||
manifestPlaceholders = ["deepLinkScheme": deepLinkSchemeValue]
|
|
||||||
}
|
|
||||||
fenixProduction releaseTemplate >> {
|
fenixProduction releaseTemplate >> {
|
||||||
applicationIdSuffix ".fenix"
|
applicationIdSuffix ".fenix"
|
||||||
buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
|
buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
|
||||||
|
@ -127,23 +113,6 @@ android {
|
||||||
"deepLinkScheme": deepLinkSchemeValue
|
"deepLinkScheme": deepLinkSchemeValue
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
fennecNightly releaseTemplate >> {
|
|
||||||
buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
|
|
||||||
applicationIdSuffix ".fennec_aurora"
|
|
||||||
def deepLinkSchemeValue = "fenix-nightly"
|
|
||||||
buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
|
|
||||||
manifestPlaceholders = [
|
|
||||||
// This release type is meant to replace Firefox (Release channel) and therefore needs to inherit
|
|
||||||
// its sharedUserId for all eternity. See:
|
|
||||||
// https://searchfox.org/mozilla-central/search?q=moz_android_shared_id&case=false®exp=false&path=
|
|
||||||
// Shipping an app update without sharedUserId can have
|
|
||||||
// fatal consequences. For example see:
|
|
||||||
// - https://issuetracker.google.com/issues/36924841
|
|
||||||
// - https://issuetracker.google.com/issues/36905922
|
|
||||||
"sharedUserId": "org.mozilla.fennec.sharedID",
|
|
||||||
"deepLinkScheme": deepLinkSchemeValue
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
variantFilter { // There's a "release" build type that exists by default that we don't use (it's replaced by "nightly" and "beta")
|
variantFilter { // There's a "release" build type that exists by default that we don't use (it's replaced by "nightly" and "beta")
|
||||||
|
@ -157,19 +126,12 @@ android {
|
||||||
// |--------------------|---------------|-----------|
|
// |--------------------|---------------|-----------|
|
||||||
// | debug | ✅ | ✅ | Both variants for testing and development.
|
// | debug | ✅ | ✅ | Both variants for testing and development.
|
||||||
// | forPerformanceTest | ✅ | ✅ | Both variants unless the perf team only cares about Nightly (TBD).
|
// | forPerformanceTest | ✅ | ✅ | Both variants unless the perf team only cares about Nightly (TBD).
|
||||||
// | fenixNightly | ✅ | ✅ | Built with both, but only the "geckoNightly" one is published to Google Play
|
// | fenixProduction | ✅ | ❌ | Fenix Production (to be renamed `Nightly`) ships with GV Nightly
|
||||||
// | fenixBeta | ❌ | ✅ | Fenix Beta ships with GV Beta
|
|
||||||
// | fenixProduction | ❌ | ✅ | Fenix Production ships with GV Beta
|
|
||||||
// | fennecProduction | ❌ | ✅ | Fenix build to replace production Firefox builds
|
// | fennecProduction | ❌ | ✅ | Fenix build to replace production Firefox builds
|
||||||
// | fennecBeta | ❌ | ✅ | Fenix build to replace beta Firefox builds
|
// | fennecBeta | ❌ | ✅ | Fenix build to replace beta Firefox builds
|
||||||
// | fennecNightly | ✅ | ❌ | Fenix build to replace Nightly Firefox builds
|
|
||||||
|
|
||||||
def flavors = flavors*.name.toString().toLowerCase()
|
def flavors = flavors*.name.toString().toLowerCase()
|
||||||
|
|
||||||
if (buildType.name == 'fenixBeta' && flavors.contains("geckonightly")) {
|
|
||||||
setIgnore true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buildType.name == 'fenixProduction' && flavors.contains("geckobeta")) {
|
if (buildType.name == 'fenixProduction' && flavors.contains("geckobeta")) {
|
||||||
setIgnore true
|
setIgnore true
|
||||||
}
|
}
|
||||||
|
@ -177,10 +139,6 @@ android {
|
||||||
if ((buildType.name == 'fennecProduction' || buildType.name == 'fennecBeta') && flavors.contains("geckonightly")) {
|
if ((buildType.name == 'fennecProduction' || buildType.name == 'fennecBeta') && flavors.contains("geckonightly")) {
|
||||||
setIgnore true
|
setIgnore true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buildType.name == 'fennecNightly' && flavors.contains("geckobeta")) {
|
|
||||||
setIgnore true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
aaptOptions {
|
aaptOptions {
|
||||||
|
@ -207,10 +165,6 @@ android {
|
||||||
androidTest {
|
androidTest {
|
||||||
resources.srcDirs += ['src/androidTest/resources']
|
resources.srcDirs += ['src/androidTest/resources']
|
||||||
}
|
}
|
||||||
fennecNightly {
|
|
||||||
java.srcDirs = ['src/migration/java']
|
|
||||||
manifest.srcFile "src/migration/AndroidManifest.xml"
|
|
||||||
}
|
|
||||||
fennecBeta {
|
fennecBeta {
|
||||||
java.srcDirs = ['src/migration/java']
|
java.srcDirs = ['src/migration/java']
|
||||||
manifest.srcFile "src/migration/AndroidManifest.xml"
|
manifest.srcFile "src/migration/AndroidManifest.xml"
|
||||||
|
|
|
@ -330,7 +330,10 @@ class BookmarksTest {
|
||||||
createBookmark(defaultWebPage.url)
|
createBookmark(defaultWebPage.url)
|
||||||
}.openTabDrawer {
|
}.openTabDrawer {
|
||||||
closeTab()
|
closeTab()
|
||||||
}.openHomeScreen { }.openThreeDotMenu {
|
}
|
||||||
|
|
||||||
|
homeScreen {
|
||||||
|
}.openThreeDotMenu {
|
||||||
}.openBookmarks {
|
}.openBookmarks {
|
||||||
bookmarksListIdlingResource =
|
bookmarksListIdlingResource =
|
||||||
RecyclerViewIdlingResource(activityTestRule.activity.findViewById(R.id.bookmark_list))
|
RecyclerViewIdlingResource(activityTestRule.activity.findViewById(R.id.bookmark_list))
|
||||||
|
|
|
@ -212,7 +212,9 @@ class HistoryTest {
|
||||||
mDevice.waitForIdle()
|
mDevice.waitForIdle()
|
||||||
}.openTabDrawer {
|
}.openTabDrawer {
|
||||||
closeTab()
|
closeTab()
|
||||||
}.openHomeScreen { }.openThreeDotMenu {
|
}
|
||||||
|
|
||||||
|
homeScreen { }.openThreeDotMenu {
|
||||||
}.openHistory {
|
}.openHistory {
|
||||||
longTapSelectItem(firstWebPage.url)
|
longTapSelectItem(firstWebPage.url)
|
||||||
openActionBarOverflowOrOptionsMenu(activityTestRule.activity)
|
openActionBarOverflowOrOptionsMenu(activityTestRule.activity)
|
||||||
|
|
|
@ -8,6 +8,7 @@ import androidx.test.uiautomator.UiSelector
|
||||||
import okhttp3.mockwebserver.MockWebServer
|
import okhttp3.mockwebserver.MockWebServer
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
|
import org.junit.Ignore
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.mozilla.fenix.helpers.AndroidAssetDispatcher
|
import org.mozilla.fenix.helpers.AndroidAssetDispatcher
|
||||||
|
@ -135,6 +136,7 @@ class MediaNotificationTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Ignore("Flaky test, temp disabled: https://github.com/mozilla-mobile/fenix/issues/12645")
|
||||||
@Test
|
@Test
|
||||||
fun mediaSystemNotificationInPrivateModeTest() {
|
fun mediaSystemNotificationInPrivateModeTest() {
|
||||||
val audioTestPage = TestAssetHelper.getAudioPageAsset(mockWebServer)
|
val audioTestPage = TestAssetHelper.getAudioPageAsset(mockWebServer)
|
||||||
|
@ -158,7 +160,7 @@ class MediaNotificationTest {
|
||||||
verifyMediaIsPaused()
|
verifyMediaIsPaused()
|
||||||
}.openTabDrawer {
|
}.openTabDrawer {
|
||||||
closeTab()
|
closeTab()
|
||||||
}.openHomeScreen { }
|
}
|
||||||
|
|
||||||
mDevice.openNotification()
|
mDevice.openNotification()
|
||||||
|
|
||||||
|
|
|
@ -58,8 +58,10 @@ class NavigationToolbarTest {
|
||||||
mDevice.waitForIdle()
|
mDevice.waitForIdle()
|
||||||
}.openNavigationToolbar {
|
}.openNavigationToolbar {
|
||||||
}.enterURLAndEnterToBrowser(nextWebPage.url) {
|
}.enterURLAndEnterToBrowser(nextWebPage.url) {
|
||||||
|
mDevice.waitForIdle()
|
||||||
verifyUrl(nextWebPage.url.toString())
|
verifyUrl(nextWebPage.url.toString())
|
||||||
mDevice.pressBack()
|
mDevice.pressBack()
|
||||||
|
mDevice.waitForIdle()
|
||||||
verifyUrl(defaultWebPage.url.toString())
|
verifyUrl(defaultWebPage.url.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -215,4 +215,39 @@ class SmokeTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun verifyETPToolbarShieldIconIsNotDisplayedIfETPIsOFFGloballyTest() {
|
||||||
|
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||||
|
|
||||||
|
homeScreen {
|
||||||
|
}.openThreeDotMenu {
|
||||||
|
}.openSettings {
|
||||||
|
}.openEnhancedTrackingProtectionSubMenu {
|
||||||
|
clickEnhancedTrackingProtectionDefaults()
|
||||||
|
verifyEnhancedTrackingProtectionOptionsGrayedOut()
|
||||||
|
}.goBackToHomeScreen {
|
||||||
|
navigationToolbar {
|
||||||
|
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||||
|
verifyEnhancedTrackingProtectionPanelNotVisible()
|
||||||
|
}.openThreeDotMenu {
|
||||||
|
}.clickAddOnsReportSiteIssue {
|
||||||
|
verifyUrl("webcompat.com/issues/new")
|
||||||
|
verifyTabCounter("2")
|
||||||
|
}.openTabDrawer {
|
||||||
|
}.openHomeScreen {
|
||||||
|
}.openThreeDotMenu {
|
||||||
|
}.openSettings {
|
||||||
|
}.openEnhancedTrackingProtectionSubMenu {
|
||||||
|
clickEnhancedTrackingProtectionDefaults()
|
||||||
|
}.goBackToHomeScreen {
|
||||||
|
}.openTabDrawer {
|
||||||
|
}.openTab(defaultWebPage.title) {
|
||||||
|
clickEnhancedTrackingProtectionPanel()
|
||||||
|
verifyEnhancedTrackingProtectionSwitch()
|
||||||
|
// Turning off TP Switch results in adding the WebPage to exception list
|
||||||
|
clickEnhancedTrackingProtectionSwitchOffOn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ class StrictEnhancedTrackingProtectionTest {
|
||||||
start()
|
start()
|
||||||
}
|
}
|
||||||
|
|
||||||
InstrumentationRegistry.getInstrumentation().context.settings().setStrictETP()
|
activityTestRule.activity.settings().setStrictETP()
|
||||||
|
|
||||||
// Reset on-boarding notification for each test
|
// Reset on-boarding notification for each test
|
||||||
TestHelper.setPreference(
|
TestHelper.setPreference(
|
||||||
|
|
|
@ -9,6 +9,7 @@ import androidx.test.uiautomator.UiDevice
|
||||||
import okhttp3.mockwebserver.MockWebServer
|
import okhttp3.mockwebserver.MockWebServer
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
|
import org.junit.BeforeClass
|
||||||
import org.junit.Ignore
|
import org.junit.Ignore
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
@ -53,6 +54,16 @@ class TabbedBrowsingTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// changing the device preference for Touch and Hold delay, to avoid long-clicks instead of a single-click
|
||||||
|
companion object {
|
||||||
|
@BeforeClass
|
||||||
|
@JvmStatic
|
||||||
|
fun setDevicePreference() {
|
||||||
|
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||||
|
mDevice.executeShellCommand("settings put secure long_press_timeout 3000")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
fun tearDown() {
|
fun tearDown() {
|
||||||
mockWebServer.shutdown()
|
mockWebServer.shutdown()
|
||||||
|
@ -118,7 +129,6 @@ class TabbedBrowsingTest {
|
||||||
verifySaveCollection()
|
verifySaveCollection()
|
||||||
}.closeAllTabs {
|
}.closeAllTabs {
|
||||||
verifyNoTabsOpened()
|
verifyNoTabsOpened()
|
||||||
}.openHomeScreen {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Repeat for Private Tabs
|
// Repeat for Private Tabs
|
||||||
|
@ -134,8 +144,6 @@ class TabbedBrowsingTest {
|
||||||
verifyCloseAllTabsButton()
|
verifyCloseAllTabsButton()
|
||||||
}.closeAllTabs {
|
}.closeAllTabs {
|
||||||
verifyNoTabsOpened()
|
verifyNoTabsOpened()
|
||||||
}.openHomeScreen {
|
|
||||||
verifyPrivateSessionMessage()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ import androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
|
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
|
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers.withResourceName
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withText
|
import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
import androidx.test.uiautomator.By
|
import androidx.test.uiautomator.By
|
||||||
|
@ -144,6 +145,8 @@ class BrowserRobot {
|
||||||
|
|
||||||
fun verifyEnhancedTrackingProtectionSwitch() = assertEnhancedTrackingProtectionSwitch()
|
fun verifyEnhancedTrackingProtectionSwitch() = assertEnhancedTrackingProtectionSwitch()
|
||||||
|
|
||||||
|
fun clickEnhancedTrackingProtectionSwitchOffOn() = onView(withResourceName("switch_widget")).click()
|
||||||
|
|
||||||
fun verifyProtectionSettingsButton() = assertProtectionSettingsButton()
|
fun verifyProtectionSettingsButton() = assertProtectionSettingsButton()
|
||||||
|
|
||||||
fun verifyEnhancedTrackingOptions() {
|
fun verifyEnhancedTrackingOptions() {
|
||||||
|
@ -188,6 +191,8 @@ class BrowserRobot {
|
||||||
|
|
||||||
fun clickEnhancedTrackingProtectionPanel() = enhancedTrackingProtectionPanel().click()
|
fun clickEnhancedTrackingProtectionPanel() = enhancedTrackingProtectionPanel().click()
|
||||||
|
|
||||||
|
fun verifyEnhancedTrackingProtectionPanelNotVisible() = assertEnhancedTrackingProtectionPanelNotVisible()
|
||||||
|
|
||||||
fun clickContextOpenLinkInNewTab() {
|
fun clickContextOpenLinkInNewTab() {
|
||||||
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||||
mDevice.waitNotNull(
|
mDevice.waitNotNull(
|
||||||
|
@ -420,6 +425,11 @@ private fun assertNavURLBar() = navURLBar()
|
||||||
|
|
||||||
fun enhancedTrackingProtectionPanel() = onView(withId(R.id.mozac_browser_toolbar_tracking_protection_indicator))
|
fun enhancedTrackingProtectionPanel() = onView(withId(R.id.mozac_browser_toolbar_tracking_protection_indicator))
|
||||||
|
|
||||||
|
private fun assertEnhancedTrackingProtectionPanelNotVisible() {
|
||||||
|
enhancedTrackingProtectionPanel()
|
||||||
|
.check(matches(withEffectiveVisibility(Visibility.GONE)))
|
||||||
|
}
|
||||||
|
|
||||||
private fun assertEnhancedTrackingProtectionSwitch() {
|
private fun assertEnhancedTrackingProtectionSwitch() {
|
||||||
withText(R.id.trackingProtectionSwitch)
|
withText(R.id.trackingProtectionSwitch)
|
||||||
.matches(withEffectiveVisibility(Visibility.VISIBLE))
|
.matches(withEffectiveVisibility(Visibility.VISIBLE))
|
||||||
|
|
|
@ -63,6 +63,7 @@ class HomeScreenRobot {
|
||||||
fun verifyHomeToolbar() = assertHomeToolbar()
|
fun verifyHomeToolbar() = assertHomeToolbar()
|
||||||
fun verifyHomeComponent() = assertHomeComponent()
|
fun verifyHomeComponent() = assertHomeComponent()
|
||||||
fun verifyDefaultSearchEngine(searchEngine: String) = verifySearchEngineIcon(searchEngine)
|
fun verifyDefaultSearchEngine(searchEngine: String) = verifySearchEngineIcon(searchEngine)
|
||||||
|
fun verifyNoTabsOpened() = assertNoTabsOpened()
|
||||||
|
|
||||||
// First Run elements
|
// First Run elements
|
||||||
fun verifyWelcomeHeader() = assertWelcomeHeader()
|
fun verifyWelcomeHeader() = assertWelcomeHeader()
|
||||||
|
@ -529,6 +530,8 @@ private fun assertHomeComponent() =
|
||||||
onView(ViewMatchers.withResourceName("sessionControlRecyclerView"))
|
onView(ViewMatchers.withResourceName("sessionControlRecyclerView"))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
|
private fun assertNoTabsOpened() = onView(withId(R.id.counter_text)).check(matches(withText("0")))
|
||||||
|
|
||||||
private fun threeDotButton() = onView(allOf(withId(R.id.menuButton)))
|
private fun threeDotButton() = onView(allOf(withId(R.id.menuButton)))
|
||||||
|
|
||||||
private fun verifySearchEngineIcon(searchEngineIcon: Bitmap, searchEngineName: String) {
|
private fun verifySearchEngineIcon(searchEngineIcon: Bitmap, searchEngineName: String) {
|
||||||
|
|
|
@ -141,6 +141,7 @@ class SettingsRobot {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun openEnhancedTrackingProtectionSubMenu(interact: SettingsSubMenuEnhancedTrackingProtectionRobot.() -> Unit): SettingsSubMenuEnhancedTrackingProtectionRobot.Transition {
|
fun openEnhancedTrackingProtectionSubMenu(interact: SettingsSubMenuEnhancedTrackingProtectionRobot.() -> Unit): SettingsSubMenuEnhancedTrackingProtectionRobot.Transition {
|
||||||
|
scrollToElementByText("Enhanced Tracking Protection")
|
||||||
fun enhancedTrackingProtectionButton() =
|
fun enhancedTrackingProtectionButton() =
|
||||||
onView(withText("Enhanced Tracking Protection"))
|
onView(withText("Enhanced Tracking Protection"))
|
||||||
enhancedTrackingProtectionButton().click()
|
enhancedTrackingProtectionButton().click()
|
||||||
|
|
|
@ -7,6 +7,7 @@ package org.mozilla.fenix.ui.robots
|
||||||
import androidx.preference.R
|
import androidx.preference.R
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.test.espresso.Espresso.onView
|
import androidx.test.espresso.Espresso.onView
|
||||||
|
import androidx.test.espresso.Espresso.pressBack
|
||||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||||
import androidx.test.espresso.contrib.RecyclerViewActions
|
import androidx.test.espresso.contrib.RecyclerViewActions
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
|
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
|
||||||
|
@ -23,9 +24,11 @@ import androidx.test.espresso.matcher.ViewMatchers.withText
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
import androidx.test.uiautomator.UiDevice
|
import androidx.test.uiautomator.UiDevice
|
||||||
import org.hamcrest.CoreMatchers.allOf
|
import org.hamcrest.CoreMatchers.allOf
|
||||||
|
import org.hamcrest.CoreMatchers.not
|
||||||
import org.mozilla.fenix.helpers.assertIsChecked
|
import org.mozilla.fenix.helpers.assertIsChecked
|
||||||
import org.mozilla.fenix.helpers.click
|
import org.mozilla.fenix.helpers.click
|
||||||
import org.mozilla.fenix.helpers.isChecked
|
import org.mozilla.fenix.helpers.isChecked
|
||||||
|
import org.mozilla.fenix.helpers.isEnabled
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of Robot Pattern for the settings Enhanced Tracking Protection sub menu.
|
* Implementation of Robot Pattern for the settings Enhanced Tracking Protection sub menu.
|
||||||
|
@ -44,8 +47,12 @@ class SettingsSubMenuEnhancedTrackingProtectionRobot {
|
||||||
|
|
||||||
fun verifyEnhancedTrackingProtectionOptions() = assertEnhancedTrackingProtectionOptions()
|
fun verifyEnhancedTrackingProtectionOptions() = assertEnhancedTrackingProtectionOptions()
|
||||||
|
|
||||||
|
fun verifyEnhancedTrackingProtectionOptionsGrayedOut() = assertEnhancedTrackingProtectionOptionsGrayedOut()
|
||||||
|
|
||||||
fun verifyEnhancedTrackingProtectionDefaults() = assertEnhancedTrackingProtectionDefaults()
|
fun verifyEnhancedTrackingProtectionDefaults() = assertEnhancedTrackingProtectionDefaults()
|
||||||
|
|
||||||
|
fun clickEnhancedTrackingProtectionDefaults() = onView(withResourceName("switch_widget")).click()
|
||||||
|
|
||||||
fun verifyRadioButtonDefaults() = assertRadioButtonDefaults()
|
fun verifyRadioButtonDefaults() = assertRadioButtonDefaults()
|
||||||
|
|
||||||
fun verifyEnhancedTrackingProtectionProtectionSubMenuItems() {
|
fun verifyEnhancedTrackingProtectionProtectionSubMenuItems() {
|
||||||
|
@ -61,6 +68,16 @@ class SettingsSubMenuEnhancedTrackingProtectionRobot {
|
||||||
class Transition {
|
class Transition {
|
||||||
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())!!
|
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())!!
|
||||||
|
|
||||||
|
fun goBackToHomeScreen(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition {
|
||||||
|
// To settings
|
||||||
|
goBackButton().click()
|
||||||
|
// To HomeScreen
|
||||||
|
pressBack()
|
||||||
|
|
||||||
|
HomeScreenRobot().interact()
|
||||||
|
return HomeScreenRobot.Transition()
|
||||||
|
}
|
||||||
|
|
||||||
fun goBack(interact: SettingsRobot.() -> Unit): SettingsRobot.Transition {
|
fun goBack(interact: SettingsRobot.() -> Unit): SettingsRobot.Transition {
|
||||||
goBackButton().click()
|
goBackButton().click()
|
||||||
|
|
||||||
|
@ -141,6 +158,31 @@ private fun assertEnhancedTrackingProtectionOptions() {
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun assertEnhancedTrackingProtectionOptionsGrayedOut() {
|
||||||
|
onView(withText("Standard (default)"))
|
||||||
|
.check(matches(not(isEnabled(true))))
|
||||||
|
|
||||||
|
val stdText = "Blocks fewer trackers. Pages will load normally."
|
||||||
|
onView(withText(stdText))
|
||||||
|
.check(matches(not(isEnabled(true))))
|
||||||
|
|
||||||
|
onView(withText("Strict"))
|
||||||
|
.check(matches(not(isEnabled(true))))
|
||||||
|
|
||||||
|
val strictText =
|
||||||
|
"Blocks more trackers, ads, and popups. Pages load faster, but some functionality might not work."
|
||||||
|
onView(withText(strictText))
|
||||||
|
.check(matches(not(isEnabled(true))))
|
||||||
|
|
||||||
|
onView(withText("Custom"))
|
||||||
|
.check(matches(not(isEnabled(true))))
|
||||||
|
|
||||||
|
val customText =
|
||||||
|
"Choose which trackers and scripts to block."
|
||||||
|
onView(withText(customText))
|
||||||
|
.check(matches(not(isEnabled(true))))
|
||||||
|
}
|
||||||
|
|
||||||
private fun assertEnhancedTrackingProtectionDefaults() {
|
private fun assertEnhancedTrackingProtectionDefaults() {
|
||||||
onView(withResourceName("switch_widget")).check(
|
onView(withResourceName("switch_widget")).check(
|
||||||
matches(
|
matches(
|
||||||
|
|
|
@ -253,12 +253,11 @@ class ThreeDotMenuMainRobot {
|
||||||
return BrowserRobot.Transition()
|
return BrowserRobot.Transition()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun closeAllTabs(interact: TabDrawerRobot.() -> Unit): TabDrawerRobot.Transition {
|
fun closeAllTabs(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition {
|
||||||
// mDevice.waitNotNull(Until.findObject(By.text("Close all tabs")), waitingTime)
|
|
||||||
closeAllTabsButton().click()
|
closeAllTabsButton().click()
|
||||||
|
|
||||||
TabDrawerRobot().interact()
|
HomeScreenRobot().interact()
|
||||||
return TabDrawerRobot.Transition()
|
return HomeScreenRobot.Transition()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun openFindInPage(interact: FindInPageRobot.() -> Unit): FindInPageRobot.Transition {
|
fun openFindInPage(interact: FindInPageRobot.() -> Unit): FindInPageRobot.Transition {
|
||||||
|
|
|
@ -10,7 +10,7 @@ import mozilla.components.concept.storage.LoginsStorage
|
||||||
import mozilla.components.lib.crash.handler.CrashHandlerService
|
import mozilla.components.lib.crash.handler.CrashHandlerService
|
||||||
import mozilla.components.service.sync.logins.GeckoLoginStorageDelegate
|
import mozilla.components.service.sync.logins.GeckoLoginStorageDelegate
|
||||||
import org.mozilla.fenix.Config
|
import org.mozilla.fenix.Config
|
||||||
import org.mozilla.fenix.utils.Settings
|
import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.geckoview.GeckoRuntime
|
import org.mozilla.geckoview.GeckoRuntime
|
||||||
import org.mozilla.geckoview.GeckoRuntimeSettings
|
import org.mozilla.geckoview.GeckoRuntimeSettings
|
||||||
|
|
||||||
|
@ -48,9 +48,10 @@ object GeckoProvider {
|
||||||
.debugLogging(Config.channel.isDebug)
|
.debugLogging(Config.channel.isDebug)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
if (!Settings.getInstance(context).shouldUseAutoSize) {
|
val settings = context.components.settings
|
||||||
|
if (!settings.shouldUseAutoSize) {
|
||||||
runtimeSettings.automaticFontSizeAdjustment = false
|
runtimeSettings.automaticFontSizeAdjustment = false
|
||||||
val fontSize = Settings.getInstance(context).fontSizeFactor
|
val fontSize = settings.fontSizeFactor
|
||||||
runtimeSettings.fontSizeFactor = fontSize
|
runtimeSettings.fontSizeFactor = fontSize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import mozilla.components.concept.storage.LoginsStorage
|
||||||
import mozilla.components.lib.crash.handler.CrashHandlerService
|
import mozilla.components.lib.crash.handler.CrashHandlerService
|
||||||
import mozilla.components.service.sync.logins.GeckoLoginStorageDelegate
|
import mozilla.components.service.sync.logins.GeckoLoginStorageDelegate
|
||||||
import org.mozilla.fenix.Config
|
import org.mozilla.fenix.Config
|
||||||
import org.mozilla.fenix.utils.Settings
|
import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.geckoview.GeckoRuntime
|
import org.mozilla.geckoview.GeckoRuntime
|
||||||
import org.mozilla.geckoview.GeckoRuntimeSettings
|
import org.mozilla.geckoview.GeckoRuntimeSettings
|
||||||
|
|
||||||
|
@ -48,9 +48,10 @@ object GeckoProvider {
|
||||||
.aboutConfigEnabled(true)
|
.aboutConfigEnabled(true)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
if (!Settings.getInstance(context).shouldUseAutoSize) {
|
val settings = context.components.settings
|
||||||
|
if (!settings.shouldUseAutoSize) {
|
||||||
runtimeSettings.automaticFontSizeAdjustment = false
|
runtimeSettings.automaticFontSizeAdjustment = false
|
||||||
val fontSize = Settings.getInstance(context).fontSizeFactor
|
val fontSize = settings.fontSizeFactor
|
||||||
runtimeSettings.fontSizeFactor = fontSize
|
runtimeSettings.fontSizeFactor = fontSize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,13 +7,10 @@ package org.mozilla.fenix
|
||||||
enum class ReleaseChannel {
|
enum class ReleaseChannel {
|
||||||
FenixDebug,
|
FenixDebug,
|
||||||
|
|
||||||
FenixNightly,
|
|
||||||
FenixBeta,
|
|
||||||
FenixProduction,
|
FenixProduction,
|
||||||
|
|
||||||
FennecProduction,
|
FennecProduction,
|
||||||
FennecBeta,
|
FennecBeta;
|
||||||
FennecNightly;
|
|
||||||
|
|
||||||
val isReleased: Boolean
|
val isReleased: Boolean
|
||||||
get() = when (this) {
|
get() = when (this) {
|
||||||
|
@ -33,8 +30,6 @@ enum class ReleaseChannel {
|
||||||
|
|
||||||
val isReleaseOrBeta: Boolean
|
val isReleaseOrBeta: Boolean
|
||||||
get() = when (this) {
|
get() = when (this) {
|
||||||
FenixProduction -> true
|
|
||||||
FenixBeta -> true
|
|
||||||
FennecProduction -> true
|
FennecProduction -> true
|
||||||
FennecBeta -> true
|
FennecBeta -> true
|
||||||
else -> false
|
else -> false
|
||||||
|
@ -43,14 +38,11 @@ enum class ReleaseChannel {
|
||||||
val isBeta: Boolean
|
val isBeta: Boolean
|
||||||
get() = when (this) {
|
get() = when (this) {
|
||||||
FennecBeta -> true
|
FennecBeta -> true
|
||||||
FenixBeta -> true
|
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
|
|
||||||
val isNightlyOrDebug: Boolean
|
val isNightlyOrDebug: Boolean
|
||||||
get() = when (this) {
|
get() = when (this) {
|
||||||
FenixNightly -> true
|
|
||||||
FennecNightly -> true
|
|
||||||
FenixDebug -> true
|
FenixDebug -> true
|
||||||
FenixProduction -> true
|
FenixProduction -> true
|
||||||
else -> false
|
else -> false
|
||||||
|
@ -66,12 +58,9 @@ enum class ReleaseChannel {
|
||||||
object Config {
|
object Config {
|
||||||
val channel = when (BuildConfig.BUILD_TYPE) {
|
val channel = when (BuildConfig.BUILD_TYPE) {
|
||||||
"fenixProduction" -> ReleaseChannel.FenixProduction
|
"fenixProduction" -> ReleaseChannel.FenixProduction
|
||||||
"fenixBeta" -> ReleaseChannel.FenixBeta
|
|
||||||
"fenixNightly" -> ReleaseChannel.FenixNightly
|
|
||||||
"debug" -> ReleaseChannel.FenixDebug
|
"debug" -> ReleaseChannel.FenixDebug
|
||||||
"fennecProduction" -> ReleaseChannel.FennecProduction
|
"fennecProduction" -> ReleaseChannel.FennecProduction
|
||||||
"fennecBeta" -> ReleaseChannel.FennecBeta
|
"fennecBeta" -> ReleaseChannel.FennecBeta
|
||||||
"fennecNightly" -> ReleaseChannel.FennecNightly
|
|
||||||
|
|
||||||
// Builds for local performance analysis, recording benchmarks, automation, etc.
|
// Builds for local performance analysis, recording benchmarks, automation, etc.
|
||||||
// This should be treated like a released channel because we want to test
|
// This should be treated like a released channel because we want to test
|
||||||
|
@ -86,7 +75,6 @@ object Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
private val fennecChannels: List<ReleaseChannel> = listOf(
|
private val fennecChannels: List<ReleaseChannel> = listOf(
|
||||||
ReleaseChannel.FennecNightly,
|
|
||||||
ReleaseChannel.FennecBeta,
|
ReleaseChannel.FennecBeta,
|
||||||
ReleaseChannel.FennecProduction
|
ReleaseChannel.FennecProduction
|
||||||
)
|
)
|
||||||
|
|
|
@ -47,7 +47,6 @@ import org.mozilla.fenix.push.WebPushEngineIntegration
|
||||||
import org.mozilla.fenix.session.PerformanceActivityLifecycleCallbacks
|
import org.mozilla.fenix.session.PerformanceActivityLifecycleCallbacks
|
||||||
import org.mozilla.fenix.session.VisibilityLifecycleCallback
|
import org.mozilla.fenix.session.VisibilityLifecycleCallback
|
||||||
import org.mozilla.fenix.utils.BrowsersCache
|
import org.mozilla.fenix.utils.BrowsersCache
|
||||||
import org.mozilla.fenix.utils.Settings
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*The main application class for Fenix. Records data to measure initialization performance.
|
*The main application class for Fenix. Records data to measure initialization performance.
|
||||||
|
@ -355,8 +354,7 @@ open class FenixApplication : LocaleAwareApplication() {
|
||||||
_, engineSession, url ->
|
_, engineSession, url ->
|
||||||
val shouldCreatePrivateSession =
|
val shouldCreatePrivateSession =
|
||||||
components.core.sessionManager.selectedSession?.private
|
components.core.sessionManager.selectedSession?.private
|
||||||
?: Settings.instance?.openLinksInAPrivateTab
|
?: components.settings.openLinksInAPrivateTab
|
||||||
?: false
|
|
||||||
|
|
||||||
val session = Session(url, shouldCreatePrivateSession)
|
val session = Session(url, shouldCreatePrivateSession)
|
||||||
components.core.sessionManager.add(session, true, engineSession)
|
components.core.sessionManager.add(session, true, engineSession)
|
||||||
|
|
|
@ -26,7 +26,6 @@ import androidx.navigation.fragment.NavHostFragment
|
||||||
import androidx.navigation.ui.AppBarConfiguration
|
import androidx.navigation.ui.AppBarConfiguration
|
||||||
import androidx.navigation.ui.NavigationUI
|
import androidx.navigation.ui.NavigationUI
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.google.android.gms.tasks.Tasks.call
|
|
||||||
import kotlinx.android.synthetic.main.activity_home.*
|
import kotlinx.android.synthetic.main.activity_home.*
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
@ -65,7 +64,6 @@ import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager
|
||||||
import org.mozilla.fenix.browser.browsingmode.DefaultBrowsingModeManager
|
import org.mozilla.fenix.browser.browsingmode.DefaultBrowsingModeManager
|
||||||
import org.mozilla.fenix.components.metrics.BreadcrumbsRecorder
|
import org.mozilla.fenix.components.metrics.BreadcrumbsRecorder
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
import org.mozilla.fenix.trackingprotectionexceptions.TrackingProtectionExceptionsFragmentDirections
|
|
||||||
import org.mozilla.fenix.ext.alreadyOnDestination
|
import org.mozilla.fenix.ext.alreadyOnDestination
|
||||||
import org.mozilla.fenix.ext.components
|
import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.fenix.ext.nav
|
import org.mozilla.fenix.ext.nav
|
||||||
|
@ -87,8 +85,8 @@ import org.mozilla.fenix.session.NotificationSessionObserver
|
||||||
import org.mozilla.fenix.settings.SettingsFragmentDirections
|
import org.mozilla.fenix.settings.SettingsFragmentDirections
|
||||||
import org.mozilla.fenix.settings.TrackingProtectionFragmentDirections
|
import org.mozilla.fenix.settings.TrackingProtectionFragmentDirections
|
||||||
import org.mozilla.fenix.settings.about.AboutFragmentDirections
|
import org.mozilla.fenix.settings.about.AboutFragmentDirections
|
||||||
import org.mozilla.fenix.settings.logins.fragment.SavedLoginsAuthFragmentDirections
|
|
||||||
import org.mozilla.fenix.settings.logins.fragment.LoginDetailFragmentDirections
|
import org.mozilla.fenix.settings.logins.fragment.LoginDetailFragmentDirections
|
||||||
|
import org.mozilla.fenix.settings.logins.fragment.SavedLoginsAuthFragmentDirections
|
||||||
import org.mozilla.fenix.settings.search.AddSearchEngineFragmentDirections
|
import org.mozilla.fenix.settings.search.AddSearchEngineFragmentDirections
|
||||||
import org.mozilla.fenix.settings.search.EditCustomSearchEngineFragmentDirections
|
import org.mozilla.fenix.settings.search.EditCustomSearchEngineFragmentDirections
|
||||||
import org.mozilla.fenix.share.AddNewDeviceFragmentDirections
|
import org.mozilla.fenix.share.AddNewDeviceFragmentDirections
|
||||||
|
@ -97,6 +95,7 @@ import org.mozilla.fenix.tabtray.FenixTabsAdapter
|
||||||
import org.mozilla.fenix.tabtray.TabTrayDialogFragment
|
import org.mozilla.fenix.tabtray.TabTrayDialogFragment
|
||||||
import org.mozilla.fenix.theme.DefaultThemeManager
|
import org.mozilla.fenix.theme.DefaultThemeManager
|
||||||
import org.mozilla.fenix.theme.ThemeManager
|
import org.mozilla.fenix.theme.ThemeManager
|
||||||
|
import org.mozilla.fenix.trackingprotectionexceptions.TrackingProtectionExceptionsFragmentDirections
|
||||||
import org.mozilla.fenix.utils.BrowsersCache
|
import org.mozilla.fenix.utils.BrowsersCache
|
||||||
import org.mozilla.fenix.utils.RunWhenReadyQueue
|
import org.mozilla.fenix.utils.RunWhenReadyQueue
|
||||||
|
|
||||||
|
@ -575,7 +574,7 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun createBrowsingModeManager(initialMode: BrowsingMode): BrowsingModeManager {
|
protected open fun createBrowsingModeManager(initialMode: BrowsingMode): BrowsingModeManager {
|
||||||
return DefaultBrowsingModeManager(initialMode) { newMode ->
|
return DefaultBrowsingModeManager(initialMode, components.settings) { newMode ->
|
||||||
themeManager.currentTheme = newMode
|
themeManager.currentTheme = newMode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,6 @@ import mozilla.components.feature.addons.ui.translatedName
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.ext.components
|
import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.fenix.ext.showToolbar
|
import org.mozilla.fenix.ext.showToolbar
|
||||||
import org.mozilla.fenix.utils.Settings
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An activity to show the details of a installed add-on.
|
* An activity to show the details of a installed add-on.
|
||||||
|
@ -191,8 +190,7 @@ class InstalledAddonDetailsFragment : Fragment() {
|
||||||
val components = it.context.components
|
val components = it.context.components
|
||||||
val shouldCreatePrivateSession =
|
val shouldCreatePrivateSession =
|
||||||
components.core.store.state.selectedTab?.content?.private
|
components.core.store.state.selectedTab?.content?.private
|
||||||
?: Settings.instance?.openLinksInAPrivateTab
|
?: components.settings.openLinksInAPrivateTab
|
||||||
?: false
|
|
||||||
|
|
||||||
if (shouldCreatePrivateSession) {
|
if (shouldCreatePrivateSession) {
|
||||||
components.useCases.tabsUseCases.addPrivateTab(settingUrl)
|
components.useCases.tabsUseCases.addPrivateTab(settingUrl)
|
||||||
|
|
|
@ -150,7 +150,8 @@ class BrowserFragment : BaseBrowserFragment(), UserInteractionHandler {
|
||||||
|
|
||||||
val toolbarSessionObserver = TrackingProtectionOverlay(
|
val toolbarSessionObserver = TrackingProtectionOverlay(
|
||||||
context = context,
|
context = context,
|
||||||
settings = settings
|
settings = settings,
|
||||||
|
metrics = context.components.analytics.metrics
|
||||||
) {
|
) {
|
||||||
browserToolbarView.view
|
browserToolbarView.view
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ interface BrowsingModeManager {
|
||||||
*/
|
*/
|
||||||
class DefaultBrowsingModeManager(
|
class DefaultBrowsingModeManager(
|
||||||
private var _mode: BrowsingMode,
|
private var _mode: BrowsingMode,
|
||||||
|
private val settings: Settings,
|
||||||
private val modeDidChange: (BrowsingMode) -> Unit
|
private val modeDidChange: (BrowsingMode) -> Unit
|
||||||
) : BrowsingModeManager {
|
) : BrowsingModeManager {
|
||||||
|
|
||||||
|
@ -44,6 +45,6 @@ class DefaultBrowsingModeManager(
|
||||||
set(value) {
|
set(value) {
|
||||||
_mode = value
|
_mode = value
|
||||||
modeDidChange(value)
|
modeDidChange(value)
|
||||||
Settings.instance?.lastKnownMode = value
|
settings.lastKnownMode = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,7 @@ import kotlinx.android.synthetic.main.tracking_protection_onboarding_popup.view.
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.components.SearchWidgetCreator
|
import org.mozilla.fenix.components.SearchWidgetCreator
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
import org.mozilla.fenix.ext.components
|
import org.mozilla.fenix.components.metrics.MetricController
|
||||||
import org.mozilla.fenix.ext.settings
|
|
||||||
import org.mozilla.fenix.utils.Settings
|
import org.mozilla.fenix.utils.Settings
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,27 +28,29 @@ import org.mozilla.fenix.utils.Settings
|
||||||
*/
|
*/
|
||||||
class SearchWidgetCFR(
|
class SearchWidgetCFR(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
|
private val settings: Settings,
|
||||||
|
private val metrics: MetricController,
|
||||||
private val getToolbar: () -> View
|
private val getToolbar: () -> View
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun displayIfNecessary() {
|
fun displayIfNecessary() {
|
||||||
if (!context.settings().isInSearchWidgetExperiment ||
|
if (settings.isInSearchWidgetExperiment &&
|
||||||
!context.settings().shouldDisplaySearchWidgetCFR() ||
|
settings.shouldDisplaySearchWidgetCFR() &&
|
||||||
isShown
|
!isShown
|
||||||
) { return }
|
) {
|
||||||
|
isShown = true
|
||||||
isShown = true
|
showSearchWidgetCFR()
|
||||||
showSearchWidgetCFR()
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("MagicNumber", "InflateParams")
|
@Suppress("InflateParams")
|
||||||
private fun showSearchWidgetCFR() {
|
private fun showSearchWidgetCFR() {
|
||||||
context.settings().incrementSearchWidgetCFRDisplayed()
|
settings.incrementSearchWidgetCFRDisplayed()
|
||||||
|
|
||||||
val searchWidgetCFRDialog = Dialog(context)
|
val searchWidgetCFRDialog = Dialog(context)
|
||||||
val layout = LayoutInflater.from(context)
|
val layout = LayoutInflater.from(context)
|
||||||
.inflate(R.layout.search_widget_cfr, null)
|
.inflate(R.layout.search_widget_cfr, null)
|
||||||
val isBottomToolbar = Settings.getInstance(context).shouldUseBottomToolbar
|
val isBottomToolbar = settings.shouldUseBottomToolbar
|
||||||
|
|
||||||
layout.drop_down_triangle.isGone = isBottomToolbar
|
layout.drop_down_triangle.isGone = isBottomToolbar
|
||||||
layout.pop_up_triangle.isVisible = isBottomToolbar
|
layout.pop_up_triangle.isVisible = isBottomToolbar
|
||||||
|
@ -63,16 +64,16 @@ class SearchWidgetCFR(
|
||||||
}
|
}
|
||||||
|
|
||||||
layout.cfr_neg_button.setOnClickListener {
|
layout.cfr_neg_button.setOnClickListener {
|
||||||
context.components.analytics.metrics.track(Event.SearchWidgetCFRNotNowPressed)
|
metrics.track(Event.SearchWidgetCFRNotNowPressed)
|
||||||
searchWidgetCFRDialog.dismiss()
|
searchWidgetCFRDialog.dismiss()
|
||||||
context.settings().manuallyDismissSearchWidgetCFR()
|
settings.manuallyDismissSearchWidgetCFR()
|
||||||
}
|
}
|
||||||
|
|
||||||
layout.cfr_pos_button.setOnClickListener {
|
layout.cfr_pos_button.setOnClickListener {
|
||||||
context.components.analytics.metrics.track(Event.SearchWidgetCFRAddWidgetPressed)
|
metrics.track(Event.SearchWidgetCFRAddWidgetPressed)
|
||||||
SearchWidgetCreator.createSearchWidget(context)
|
SearchWidgetCreator.createSearchWidget(context)
|
||||||
searchWidgetCFRDialog.dismiss()
|
searchWidgetCFRDialog.dismiss()
|
||||||
context.settings().manuallyDismissSearchWidgetCFR()
|
settings.manuallyDismissSearchWidgetCFR()
|
||||||
}
|
}
|
||||||
|
|
||||||
searchWidgetCFRDialog.apply {
|
searchWidgetCFRDialog.apply {
|
||||||
|
@ -90,16 +91,16 @@ class SearchWidgetCFR(
|
||||||
|
|
||||||
searchWidgetCFRDialog.setOnCancelListener {
|
searchWidgetCFRDialog.setOnCancelListener {
|
||||||
isShown = false
|
isShown = false
|
||||||
context.components.analytics.metrics.track(Event.SearchWidgetCFRCanceled)
|
metrics.track(Event.SearchWidgetCFRCanceled)
|
||||||
}
|
}
|
||||||
|
|
||||||
searchWidgetCFRDialog.setOnDismissListener {
|
searchWidgetCFRDialog.setOnDismissListener {
|
||||||
isShown = false
|
isShown = false
|
||||||
context.settings().incrementSearchWidgetCFRDismissed()
|
settings.incrementSearchWidgetCFRDismissed()
|
||||||
}
|
}
|
||||||
|
|
||||||
searchWidgetCFRDialog.show()
|
searchWidgetCFRDialog.show()
|
||||||
context.components.analytics.metrics.track(Event.SearchWidgetCFRDisplayed)
|
metrics.track(Event.SearchWidgetCFRDisplayed)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
@ -10,6 +10,7 @@ import org.mozilla.fenix.home.Tab
|
||||||
/**
|
/**
|
||||||
* Diff callback for comparing tab lists with selected state.
|
* Diff callback for comparing tab lists with selected state.
|
||||||
*/
|
*/
|
||||||
|
@Suppress("LongParameterList")
|
||||||
internal class TabDiffUtil(
|
internal class TabDiffUtil(
|
||||||
private val old: List<Tab>,
|
private val old: List<Tab>,
|
||||||
private val new: List<Tab>,
|
private val new: List<Tab>,
|
||||||
|
|
|
@ -103,11 +103,8 @@ private fun getSentryProjectUrl(): String? {
|
||||||
val baseUrl = "https://sentry.prod.mozaws.net/operations"
|
val baseUrl = "https://sentry.prod.mozaws.net/operations"
|
||||||
return when (Config.channel) {
|
return when (Config.channel) {
|
||||||
ReleaseChannel.FenixProduction -> "$baseUrl/fenix"
|
ReleaseChannel.FenixProduction -> "$baseUrl/fenix"
|
||||||
ReleaseChannel.FenixBeta -> "$baseUrl/fenix-beta"
|
|
||||||
ReleaseChannel.FenixNightly -> "$baseUrl/fenix-nightly"
|
|
||||||
ReleaseChannel.FennecProduction -> "$baseUrl/fenix-fennec"
|
ReleaseChannel.FennecProduction -> "$baseUrl/fenix-fennec"
|
||||||
ReleaseChannel.FennecBeta -> "$baseUrl/fenix-fennec-beta"
|
ReleaseChannel.FennecBeta -> "$baseUrl/fenix-fennec-beta"
|
||||||
ReleaseChannel.FennecNightly -> "$baseUrl/fenix-fennec-nightly"
|
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@ import org.mozilla.fenix.ext.settings
|
||||||
import org.mozilla.fenix.sync.SyncedTabsIntegration
|
import org.mozilla.fenix.sync.SyncedTabsIntegration
|
||||||
import org.mozilla.fenix.utils.Mockable
|
import org.mozilla.fenix.utils.Mockable
|
||||||
import org.mozilla.fenix.utils.RunWhenReadyQueue
|
import org.mozilla.fenix.utils.RunWhenReadyQueue
|
||||||
|
import org.mozilla.fenix.utils.Settings
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component group for background services. These are the components that need to be accessed from within a
|
* Component group for background services. These are the components that need to be accessed from within a
|
||||||
|
@ -103,7 +104,7 @@ class BackgroundServices(
|
||||||
}
|
}
|
||||||
|
|
||||||
private val telemetryAccountObserver = TelemetryAccountObserver(
|
private val telemetryAccountObserver = TelemetryAccountObserver(
|
||||||
context,
|
context.settings(),
|
||||||
context.components.analytics.metrics
|
context.components.analytics.metrics
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -178,8 +179,8 @@ class BackgroundServices(
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting(otherwise = PRIVATE)
|
@VisibleForTesting(otherwise = PRIVATE)
|
||||||
class TelemetryAccountObserver(
|
internal class TelemetryAccountObserver(
|
||||||
private val context: Context,
|
private val settings: Settings,
|
||||||
private val metricController: MetricController
|
private val metricController: MetricController
|
||||||
) : AccountObserver {
|
) : AccountObserver {
|
||||||
override fun onAuthenticated(account: OAuthAccount, authType: AuthType) {
|
override fun onAuthenticated(account: OAuthAccount, authType: AuthType) {
|
||||||
|
@ -211,12 +212,12 @@ class TelemetryAccountObserver(
|
||||||
metricController.track(Event.SyncAuthOtherExternal)
|
metricController.track(Event.SyncAuthOtherExternal)
|
||||||
}
|
}
|
||||||
// Used by Leanplum as a context variable.
|
// Used by Leanplum as a context variable.
|
||||||
context.settings().fxaSignedIn = true
|
settings.fxaSignedIn = true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onLoggedOut() {
|
override fun onLoggedOut() {
|
||||||
metricController.track(Event.SyncAuthSignOut)
|
metricController.track(Event.SyncAuthSignOut)
|
||||||
// Used by Leanplum as a context variable.
|
// Used by Leanplum as a context variable.
|
||||||
context.settings().fxaSignedIn = false
|
settings.fxaSignedIn = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import org.mozilla.fenix.BuildConfig
|
||||||
import org.mozilla.fenix.HomeActivity
|
import org.mozilla.fenix.HomeActivity
|
||||||
import org.mozilla.fenix.utils.ClipboardHandler
|
import org.mozilla.fenix.utils.ClipboardHandler
|
||||||
import org.mozilla.fenix.utils.Mockable
|
import org.mozilla.fenix.utils.Mockable
|
||||||
|
import org.mozilla.fenix.utils.Settings
|
||||||
import org.mozilla.fenix.wifi.WifiConnectionMonitor
|
import org.mozilla.fenix.wifi.WifiConnectionMonitor
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
@ -107,4 +108,6 @@ class Components(private val context: Context) {
|
||||||
val performance by lazy { PerformanceComponent() }
|
val performance by lazy { PerformanceComponent() }
|
||||||
val push by lazy { Push(context, analytics.crashReporter) }
|
val push by lazy { Push(context, analytics.crashReporter) }
|
||||||
val wifiConnectionMonitor by lazy { WifiConnectionMonitor(context.getSystemService()!!) }
|
val wifiConnectionMonitor by lazy { WifiConnectionMonitor(context.getSystemService()!!) }
|
||||||
|
|
||||||
|
val settings by lazy { Settings(context) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ import com.adjust.sdk.AdjustConfig
|
||||||
import com.adjust.sdk.LogLevel
|
import com.adjust.sdk.LogLevel
|
||||||
import org.mozilla.fenix.BuildConfig
|
import org.mozilla.fenix.BuildConfig
|
||||||
import org.mozilla.fenix.Config
|
import org.mozilla.fenix.Config
|
||||||
import org.mozilla.fenix.ReleaseChannel
|
|
||||||
import org.mozilla.fenix.ext.settings
|
import org.mozilla.fenix.ext.settings
|
||||||
|
|
||||||
class AdjustMetricsService(private val application: Application) : MetricsService {
|
class AdjustMetricsService(private val application: Application) : MetricsService {
|
||||||
|
@ -23,7 +22,7 @@ class AdjustMetricsService(private val application: Application) : MetricsServic
|
||||||
if ((BuildConfig.ADJUST_TOKEN.isNullOrBlank())) {
|
if ((BuildConfig.ADJUST_TOKEN.isNullOrBlank())) {
|
||||||
Log.i(LOGTAG, "No adjust token defined")
|
Log.i(LOGTAG, "No adjust token defined")
|
||||||
|
|
||||||
if (Config.channel.isReleased && Config.channel != ReleaseChannel.FennecNightly) {
|
if (Config.channel.isReleased) {
|
||||||
throw IllegalStateException("No adjust token defined for release build")
|
throw IllegalStateException("No adjust token defined for release build")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,15 +24,14 @@ import mozilla.components.browser.state.selector.findTab
|
||||||
import mozilla.components.browser.state.store.BrowserStore
|
import mozilla.components.browser.state.store.BrowserStore
|
||||||
import mozilla.components.concept.storage.BookmarksStorage
|
import mozilla.components.concept.storage.BookmarksStorage
|
||||||
import mozilla.components.support.ktx.android.content.getColorFromAttr
|
import mozilla.components.support.ktx.android.content.getColorFromAttr
|
||||||
import org.mozilla.fenix.R
|
|
||||||
import org.mozilla.fenix.FeatureFlags
|
import org.mozilla.fenix.FeatureFlags
|
||||||
import org.mozilla.fenix.HomeActivity
|
import org.mozilla.fenix.HomeActivity
|
||||||
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
|
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
|
||||||
import org.mozilla.fenix.ext.asActivity
|
import org.mozilla.fenix.ext.asActivity
|
||||||
import org.mozilla.fenix.ext.components
|
import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.fenix.ext.settings
|
import org.mozilla.fenix.ext.settings
|
||||||
import org.mozilla.fenix.theme.ThemeManager
|
import org.mozilla.fenix.theme.ThemeManager
|
||||||
import org.mozilla.fenix.utils.Settings
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds the toolbar object used with the 3-dot menu in the browser fragment.
|
* Builds the toolbar object used with the 3-dot menu in the browser fragment.
|
||||||
|
@ -160,7 +159,7 @@ class DefaultToolbarMenu(
|
||||||
// Predicates that are called once, during screen init
|
// Predicates that are called once, during screen init
|
||||||
val shouldShowSaveToCollection = (context.asActivity() as? HomeActivity)
|
val shouldShowSaveToCollection = (context.asActivity() as? HomeActivity)
|
||||||
?.browsingModeManager?.mode == BrowsingMode.Normal
|
?.browsingModeManager?.mode == BrowsingMode.Normal
|
||||||
val shouldDeleteDataOnQuit = Settings.getInstance(context)
|
val shouldDeleteDataOnQuit = context.components.settings
|
||||||
.shouldDeleteBrowsingDataOnQuit
|
.shouldDeleteBrowsingDataOnQuit
|
||||||
|
|
||||||
val menuItems = listOfNotNull(
|
val menuItems = listOfNotNull(
|
||||||
|
|
|
@ -12,13 +12,10 @@ import android.view.ViewGroup
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import mozilla.components.browser.search.SearchEngineManager
|
import mozilla.components.browser.search.SearchEngineManager
|
||||||
import mozilla.components.support.locale.LocaleManager
|
import mozilla.components.support.locale.LocaleManager
|
||||||
import org.mozilla.fenix.BuildConfig
|
|
||||||
import org.mozilla.fenix.Config
|
|
||||||
import org.mozilla.fenix.FenixApplication
|
import org.mozilla.fenix.FenixApplication
|
||||||
import org.mozilla.fenix.components.Components
|
import org.mozilla.fenix.components.Components
|
||||||
import org.mozilla.fenix.components.metrics.MetricController
|
import org.mozilla.fenix.components.metrics.MetricController
|
||||||
import org.mozilla.fenix.settings.advanced.getSelectedLocale
|
import org.mozilla.fenix.settings.advanced.getSelectedLocale
|
||||||
import org.mozilla.fenix.utils.Settings
|
|
||||||
import java.lang.String.format
|
import java.lang.String.format
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
|
@ -60,8 +57,7 @@ fun Context.getPreferenceKey(@StringRes resourceId: Int): String =
|
||||||
fun Context.getRootView(): View? =
|
fun Context.getRootView(): View? =
|
||||||
asActivity()?.window?.decorView?.findViewById<View>(android.R.id.content) as? ViewGroup
|
asActivity()?.window?.decorView?.findViewById<View>(android.R.id.content) as? ViewGroup
|
||||||
|
|
||||||
fun Context.settings(isCrashReportEnabledInBuild: Boolean = BuildConfig.CRASH_REPORTING && Config.channel.isReleased) =
|
fun Context.settings() = components.settings
|
||||||
Settings.getInstance(this, isCrashReportEnabledInBuild)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to catch IllegalArgumentException that is thrown when
|
* Used to catch IllegalArgumentException that is thrown when
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/* 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.ext
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.text.Spannable
|
||||||
|
import android.text.SpannableString
|
||||||
|
import android.text.style.AbsoluteSizeSpan
|
||||||
|
import android.text.style.ForegroundColorSpan
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import mozilla.components.support.ktx.android.util.dpToPx
|
||||||
|
|
||||||
|
fun SpannableString.setTextSize(context: Context, textSize: Int) =
|
||||||
|
this.setSpan(
|
||||||
|
AbsoluteSizeSpan(textSize.dpToPx(context.resources.displayMetrics)),
|
||||||
|
0,
|
||||||
|
this.length,
|
||||||
|
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||||
|
)
|
||||||
|
|
||||||
|
fun SpannableString.setTextColor(context: Context, colorResId: Int) =
|
||||||
|
this.setSpan(
|
||||||
|
ForegroundColorSpan(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
context,
|
||||||
|
colorResId
|
||||||
|
)
|
||||||
|
),
|
||||||
|
0,
|
||||||
|
this.length,
|
||||||
|
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||||
|
)
|
|
@ -375,7 +375,13 @@ class HomeFragment : Fragment() {
|
||||||
// the CFR in.
|
// the CFR in.
|
||||||
view.toolbar_wrapper.doOnLayout {
|
view.toolbar_wrapper.doOnLayout {
|
||||||
if (!browsingModeManager.mode.isPrivate) {
|
if (!browsingModeManager.mode.isPrivate) {
|
||||||
SearchWidgetCFR(view.context) { view.toolbar_wrapper }.displayIfNecessary()
|
SearchWidgetCFR(
|
||||||
|
context = view.context,
|
||||||
|
settings = view.context.settings(),
|
||||||
|
metrics = view.context.components.analytics.metrics
|
||||||
|
) {
|
||||||
|
view.toolbar_wrapper
|
||||||
|
}.displayIfNecessary()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,6 @@ import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.ext.components
|
import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.fenix.ext.settings
|
import org.mozilla.fenix.ext.settings
|
||||||
import org.mozilla.fenix.theme.ThemeManager
|
import org.mozilla.fenix.theme.ThemeManager
|
||||||
import org.mozilla.fenix.utils.Settings
|
|
||||||
import org.mozilla.fenix.whatsnew.WhatsNew
|
import org.mozilla.fenix.whatsnew.WhatsNew
|
||||||
|
|
||||||
class HomeMenu(
|
class HomeMenu(
|
||||||
|
@ -153,40 +152,29 @@ class HomeMenu(
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val settings = context.components.settings
|
||||||
|
|
||||||
|
val menuItems = listOfNotNull(
|
||||||
|
if (settings.shouldDeleteBrowsingDataOnQuit) quitItem else null,
|
||||||
|
settingsItem,
|
||||||
|
BrowserMenuDivider(),
|
||||||
|
if (FeatureFlags.syncedTabs) syncedTabsItem else null,
|
||||||
|
bookmarksItem,
|
||||||
|
historyItem,
|
||||||
|
BrowserMenuDivider(),
|
||||||
|
addons,
|
||||||
|
BrowserMenuDivider(),
|
||||||
|
whatsNewItem,
|
||||||
|
helpItem,
|
||||||
|
accountAuthItem
|
||||||
|
).also { items ->
|
||||||
|
items.getHighlight()?.let { onHighlightPresent(it) }
|
||||||
|
}
|
||||||
|
|
||||||
if (shouldUseBottomToolbar) {
|
if (shouldUseBottomToolbar) {
|
||||||
listOfNotNull(
|
menuItems.reversed()
|
||||||
accountAuthItem,
|
|
||||||
helpItem,
|
|
||||||
whatsNewItem,
|
|
||||||
BrowserMenuDivider(),
|
|
||||||
addons,
|
|
||||||
BrowserMenuDivider(),
|
|
||||||
historyItem,
|
|
||||||
bookmarksItem,
|
|
||||||
if (FeatureFlags.syncedTabs) syncedTabsItem else null,
|
|
||||||
BrowserMenuDivider(),
|
|
||||||
settingsItem,
|
|
||||||
if (Settings.getInstance(context).shouldDeleteBrowsingDataOnQuit) quitItem else null
|
|
||||||
).also { items ->
|
|
||||||
items.getHighlight()?.let { onHighlightPresent(it) }
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
listOfNotNull(
|
menuItems
|
||||||
if (Settings.getInstance(context).shouldDeleteBrowsingDataOnQuit) quitItem else null,
|
|
||||||
settingsItem,
|
|
||||||
BrowserMenuDivider(),
|
|
||||||
if (FeatureFlags.syncedTabs) syncedTabsItem else null,
|
|
||||||
bookmarksItem,
|
|
||||||
historyItem,
|
|
||||||
BrowserMenuDivider(),
|
|
||||||
addons,
|
|
||||||
BrowserMenuDivider(),
|
|
||||||
whatsNewItem,
|
|
||||||
helpItem,
|
|
||||||
accountAuthItem
|
|
||||||
).also { items ->
|
|
||||||
items.getHighlight()?.let { onHighlightPresent(it) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -128,7 +128,7 @@ interface SessionControlController {
|
||||||
fun handleCreateCollection()
|
fun handleCreateCollection()
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("TooManyFunctions", "LargeClass")
|
@SuppressWarnings("TooManyFunctions", "LargeClass", "LongParameterList")
|
||||||
class DefaultSessionControlController(
|
class DefaultSessionControlController(
|
||||||
private val activity: HomeActivity,
|
private val activity: HomeActivity,
|
||||||
private val engine: Engine,
|
private val engine: Engine,
|
||||||
|
|
|
@ -12,12 +12,13 @@ import org.mozilla.fenix.components.metrics.Event
|
||||||
import org.mozilla.fenix.components.metrics.Event.OnboardingToolbarPosition.Position
|
import org.mozilla.fenix.components.metrics.Event.OnboardingToolbarPosition.Position
|
||||||
import org.mozilla.fenix.ext.asActivity
|
import org.mozilla.fenix.ext.asActivity
|
||||||
import org.mozilla.fenix.ext.components
|
import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.fenix.ext.settings
|
|
||||||
import org.mozilla.fenix.onboarding.OnboardingRadioButton
|
import org.mozilla.fenix.onboarding.OnboardingRadioButton
|
||||||
import org.mozilla.fenix.utils.view.addToRadioGroup
|
import org.mozilla.fenix.utils.view.addToRadioGroup
|
||||||
|
|
||||||
class OnboardingToolbarPositionPickerViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
class OnboardingToolbarPositionPickerViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||||
|
|
||||||
|
private val metrics = view.context.components.analytics.metrics
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val radioTopToolbar = view.toolbar_top_radio_button
|
val radioTopToolbar = view.toolbar_top_radio_button
|
||||||
val radioBottomToolbar = view.toolbar_bottom_radio_button
|
val radioBottomToolbar = view.toolbar_bottom_radio_button
|
||||||
|
@ -27,7 +28,8 @@ class OnboardingToolbarPositionPickerViewHolder(view: View) : RecyclerView.ViewH
|
||||||
radioTopToolbar.addIllustration(view.toolbar_top_image)
|
radioTopToolbar.addIllustration(view.toolbar_top_image)
|
||||||
radioBottomToolbar.addIllustration(view.toolbar_bottom_image)
|
radioBottomToolbar.addIllustration(view.toolbar_bottom_image)
|
||||||
|
|
||||||
radio = if (view.context.settings().shouldUseBottomToolbar) {
|
val settings = view.context.components.settings
|
||||||
|
radio = if (settings.shouldUseBottomToolbar) {
|
||||||
radioBottomToolbar
|
radioBottomToolbar
|
||||||
} else {
|
} else {
|
||||||
radioTopToolbar
|
radioTopToolbar
|
||||||
|
@ -35,28 +37,24 @@ class OnboardingToolbarPositionPickerViewHolder(view: View) : RecyclerView.ViewH
|
||||||
radio.updateRadioValue(true)
|
radio.updateRadioValue(true)
|
||||||
|
|
||||||
radioBottomToolbar.onClickListener {
|
radioBottomToolbar.onClickListener {
|
||||||
itemView.context.components.analytics.metrics
|
metrics.track(Event.OnboardingToolbarPosition(Position.BOTTOM))
|
||||||
.track(Event.OnboardingToolbarPosition(Position.BOTTOM))
|
|
||||||
|
|
||||||
itemView.context.asActivity()?.recreate()
|
itemView.context.asActivity()?.recreate()
|
||||||
}
|
}
|
||||||
|
|
||||||
view.toolbar_bottom_image.setOnClickListener {
|
view.toolbar_bottom_image.setOnClickListener {
|
||||||
itemView.context.components.analytics.metrics
|
metrics.track(Event.OnboardingToolbarPosition(Position.BOTTOM))
|
||||||
.track(Event.OnboardingToolbarPosition(Position.BOTTOM))
|
|
||||||
|
|
||||||
radioBottomToolbar.performClick()
|
radioBottomToolbar.performClick()
|
||||||
}
|
}
|
||||||
|
|
||||||
radioTopToolbar.onClickListener {
|
radioTopToolbar.onClickListener {
|
||||||
itemView.context.components.analytics.metrics
|
metrics.track(Event.OnboardingToolbarPosition(Position.TOP))
|
||||||
.track(Event.OnboardingToolbarPosition(Position.TOP))
|
|
||||||
itemView.context.asActivity()?.recreate()
|
itemView.context.asActivity()?.recreate()
|
||||||
}
|
}
|
||||||
|
|
||||||
view.toolbar_top_image.setOnClickListener {
|
view.toolbar_top_image.setOnClickListener {
|
||||||
itemView.context.components.analytics.metrics
|
metrics.track(Event.OnboardingToolbarPosition(Position.TOP))
|
||||||
.track(Event.OnboardingToolbarPosition(Position.TOP))
|
|
||||||
radioTopToolbar.performClick()
|
radioTopToolbar.performClick()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,17 +37,17 @@ class OnboardingTrackingProtectionViewHolder(view: View) : RecyclerView.ViewHold
|
||||||
isChecked = view.context.settings().shouldUseTrackingProtection
|
isChecked = view.context.settings().shouldUseTrackingProtection
|
||||||
setOnCheckedChangeListener { _, isChecked ->
|
setOnCheckedChangeListener { _, isChecked ->
|
||||||
updateTrackingProtectionSetting(isChecked)
|
updateTrackingProtectionSetting(isChecked)
|
||||||
updateRadioGroupState(view, isChecked)
|
updateRadioGroupState(isChecked)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setupRadioGroup(view, trackingProtectionToggle.isChecked)
|
setupRadioGroup(trackingProtectionToggle.isChecked)
|
||||||
updateRadioGroupState(view, trackingProtectionToggle.isChecked)
|
updateRadioGroupState(trackingProtectionToggle.isChecked)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupRadioGroup(view: View, isChecked: Boolean) {
|
private fun setupRadioGroup(isChecked: Boolean) {
|
||||||
|
|
||||||
updateRadioGroupState(view, isChecked)
|
updateRadioGroupState(isChecked)
|
||||||
|
|
||||||
addToRadioGroup(standardTrackingProtection, strictTrackingProtection)
|
addToRadioGroup(standardTrackingProtection, strictTrackingProtection)
|
||||||
|
|
||||||
|
@ -58,56 +58,20 @@ class OnboardingTrackingProtectionViewHolder(view: View) : RecyclerView.ViewHold
|
||||||
|
|
||||||
standardTrackingProtection.onClickListener {
|
standardTrackingProtection.onClickListener {
|
||||||
updateTrackingProtectionPolicy()
|
updateTrackingProtectionPolicy()
|
||||||
view.context.components.analytics.metrics
|
itemView.context.components.analytics.metrics
|
||||||
.track(Event.OnboardingTrackingProtection(Setting.STANDARD))
|
.track(Event.OnboardingTrackingProtection(Setting.STANDARD))
|
||||||
}
|
}
|
||||||
|
|
||||||
view.clickable_region_standard.apply {
|
|
||||||
setOnClickListener {
|
|
||||||
standardTrackingProtection.performClick()
|
|
||||||
view.context.components.analytics.metrics
|
|
||||||
.track(Event.OnboardingTrackingProtection(Setting.STANDARD))
|
|
||||||
}
|
|
||||||
val standardTitle = view.context.getString(
|
|
||||||
R.string.onboarding_tracking_protection_standard_button_2
|
|
||||||
)
|
|
||||||
val standardSummary = view.context.getString(
|
|
||||||
R.string.onboarding_tracking_protection_standard_button_description_2
|
|
||||||
)
|
|
||||||
contentDescription = "$standardTitle. $standardSummary"
|
|
||||||
}
|
|
||||||
|
|
||||||
strictTrackingProtection.onClickListener {
|
strictTrackingProtection.onClickListener {
|
||||||
updateTrackingProtectionPolicy()
|
updateTrackingProtectionPolicy()
|
||||||
view.context.components.analytics.metrics
|
itemView.context.components.analytics.metrics
|
||||||
.track(Event.OnboardingTrackingProtection(Setting.STRICT))
|
.track(Event.OnboardingTrackingProtection(Setting.STRICT))
|
||||||
}
|
}
|
||||||
|
|
||||||
view.clickable_region_strict.apply {
|
|
||||||
setOnClickListener {
|
|
||||||
strictTrackingProtection.performClick()
|
|
||||||
view.context.components.analytics.metrics
|
|
||||||
.track(Event.OnboardingTrackingProtection(Setting.STRICT))
|
|
||||||
}
|
|
||||||
val strictTitle =
|
|
||||||
view.context.getString(R.string.onboarding_tracking_protection_strict_option)
|
|
||||||
val strictSummary =
|
|
||||||
view.context.getString(R.string.onboarding_tracking_protection_strict_button_description_2)
|
|
||||||
contentDescription = "$strictTitle. $strictSummary"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateRadioGroupState(view: View, isChecked: Boolean) {
|
private fun updateRadioGroupState(isChecked: Boolean) {
|
||||||
standardTrackingProtection.isEnabled = isChecked
|
standardTrackingProtection.isEnabled = isChecked
|
||||||
strictTrackingProtection.isEnabled = isChecked
|
strictTrackingProtection.isEnabled = isChecked
|
||||||
|
|
||||||
view.protection_standard_description.isEnabled = isChecked
|
|
||||||
view.protection_strict_description.isEnabled = isChecked
|
|
||||||
view.clickable_region_standard.isClickable = isChecked
|
|
||||||
|
|
||||||
view.protection_standard_title.isEnabled = isChecked
|
|
||||||
view.protection_strict_title.isEnabled = isChecked
|
|
||||||
view.clickable_region_strict.isClickable = isChecked
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateTrackingProtectionSetting(enabled: Boolean) {
|
private fun updateTrackingProtectionSetting(enabled: Boolean) {
|
||||||
|
|
|
@ -47,7 +47,7 @@ interface BookmarkController {
|
||||||
fun handleBackPressed()
|
fun handleBackPressed()
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("TooManyFunctions")
|
@SuppressWarnings("TooManyFunctions", "LongParameterList")
|
||||||
class DefaultBookmarkController(
|
class DefaultBookmarkController(
|
||||||
private val activity: HomeActivity,
|
private val activity: HomeActivity,
|
||||||
private val navController: NavController,
|
private val navController: NavController,
|
||||||
|
|
|
@ -51,6 +51,7 @@ import org.mozilla.fenix.ext.nav
|
||||||
import org.mozilla.fenix.ext.requireComponents
|
import org.mozilla.fenix.ext.requireComponents
|
||||||
import org.mozilla.fenix.ext.toShortUrl
|
import org.mozilla.fenix.ext.toShortUrl
|
||||||
import org.mozilla.fenix.library.LibraryPageFragment
|
import org.mozilla.fenix.library.LibraryPageFragment
|
||||||
|
import org.mozilla.fenix.tabtray.TabTrayDialogFragment
|
||||||
import org.mozilla.fenix.utils.allowUndo
|
import org.mozilla.fenix.utils.allowUndo
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -207,14 +208,14 @@ class BookmarkFragment : LibraryPageFragment<BookmarkNode>(), UserInteractionHan
|
||||||
R.id.open_bookmarks_in_new_tabs_multi_select -> {
|
R.id.open_bookmarks_in_new_tabs_multi_select -> {
|
||||||
openItemsInNewTab { node -> node.url }
|
openItemsInNewTab { node -> node.url }
|
||||||
|
|
||||||
navigate(BookmarkFragmentDirections.actionGlobalTabTrayDialogFragment())
|
showTabTray()
|
||||||
metrics?.track(Event.OpenedBookmarksInNewTabs)
|
metrics?.track(Event.OpenedBookmarksInNewTabs)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
R.id.open_bookmarks_in_private_tabs_multi_select -> {
|
R.id.open_bookmarks_in_private_tabs_multi_select -> {
|
||||||
openItemsInNewTab(private = true) { node -> node.url }
|
openItemsInNewTab(private = true) { node -> node.url }
|
||||||
|
|
||||||
navigate(BookmarkFragmentDirections.actionGlobalTabTrayDialogFragment())
|
showTabTray()
|
||||||
metrics?.track(Event.OpenedBookmarksInPrivateTabs)
|
metrics?.track(Event.OpenedBookmarksInPrivateTabs)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -237,6 +238,11 @@ class BookmarkFragment : LibraryPageFragment<BookmarkNode>(), UserInteractionHan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun showTabTray() {
|
||||||
|
invokePendingDeletion()
|
||||||
|
TabTrayDialogFragment.show(parentFragmentManager)
|
||||||
|
}
|
||||||
|
|
||||||
private fun navigate(directions: NavDirections) {
|
private fun navigate(directions: NavDirections) {
|
||||||
invokePendingDeletion()
|
invokePendingDeletion()
|
||||||
findNavController().nav(
|
findNavController().nav(
|
||||||
|
|
|
@ -44,6 +44,7 @@ import org.mozilla.fenix.ext.requireComponents
|
||||||
import org.mozilla.fenix.ext.showToolbar
|
import org.mozilla.fenix.ext.showToolbar
|
||||||
import org.mozilla.fenix.ext.toShortUrl
|
import org.mozilla.fenix.ext.toShortUrl
|
||||||
import org.mozilla.fenix.library.LibraryPageFragment
|
import org.mozilla.fenix.library.LibraryPageFragment
|
||||||
|
import org.mozilla.fenix.tabtray.TabTrayDialogFragment
|
||||||
import org.mozilla.fenix.utils.allowUndo
|
import org.mozilla.fenix.utils.allowUndo
|
||||||
|
|
||||||
@SuppressWarnings("TooManyFunctions", "LargeClass")
|
@SuppressWarnings("TooManyFunctions", "LargeClass")
|
||||||
|
@ -184,9 +185,7 @@ class HistoryFragment : LibraryPageFragment<HistoryItem>(), UserInteractionHandl
|
||||||
selectedItem.url
|
selectedItem.url
|
||||||
}
|
}
|
||||||
|
|
||||||
navigate(
|
showTabTray()
|
||||||
HistoryFragmentDirections.actionGlobalTabTrayDialogFragment()
|
|
||||||
)
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
R.id.open_history_in_private_tabs_multi_select -> {
|
R.id.open_history_in_private_tabs_multi_select -> {
|
||||||
|
@ -199,14 +198,18 @@ class HistoryFragment : LibraryPageFragment<HistoryItem>(), UserInteractionHandl
|
||||||
browsingModeManager.mode = BrowsingMode.Private
|
browsingModeManager.mode = BrowsingMode.Private
|
||||||
supportActionBar?.hide()
|
supportActionBar?.hide()
|
||||||
}
|
}
|
||||||
navigate(
|
|
||||||
HistoryFragmentDirections.actionGlobalTabTrayDialogFragment()
|
showTabTray()
|
||||||
)
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
else -> super.onOptionsItemSelected(item)
|
else -> super.onOptionsItemSelected(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun showTabTray() {
|
||||||
|
invokePendingDeletion()
|
||||||
|
TabTrayDialogFragment.show(parentFragmentManager)
|
||||||
|
}
|
||||||
|
|
||||||
private fun getMultiSelectSnackBarMessage(historyItems: Set<HistoryItem>): String {
|
private fun getMultiSelectSnackBarMessage(historyItems: Set<HistoryItem>): String {
|
||||||
return if (historyItems.size > 1) {
|
return if (historyItems.size > 1) {
|
||||||
getString(R.string.history_delete_multiple_items_snackbar)
|
getString(R.string.history_delete_multiple_items_snackbar)
|
||||||
|
|
|
@ -5,12 +5,16 @@
|
||||||
package org.mozilla.fenix.onboarding
|
package org.mozilla.fenix.onboarding
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.text.SpannableString
|
||||||
|
import android.text.SpannableStringBuilder
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import androidx.appcompat.widget.AppCompatRadioButton
|
import androidx.appcompat.widget.AppCompatRadioButton
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import androidx.core.content.withStyledAttributes
|
import androidx.core.content.withStyledAttributes
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.ext.setTextColor
|
||||||
|
import org.mozilla.fenix.ext.setTextSize
|
||||||
import org.mozilla.fenix.ext.settings
|
import org.mozilla.fenix.ext.settings
|
||||||
import org.mozilla.fenix.utils.view.GroupableRadioButton
|
import org.mozilla.fenix.utils.view.GroupableRadioButton
|
||||||
import org.mozilla.fenix.utils.view.uncheckAll
|
import org.mozilla.fenix.utils.view.uncheckAll
|
||||||
|
@ -23,6 +27,8 @@ class OnboardingRadioButton(
|
||||||
private var illustration: ImageView? = null
|
private var illustration: ImageView? = null
|
||||||
private var clickListener: (() -> Unit)? = null
|
private var clickListener: (() -> Unit)? = null
|
||||||
var key: Int = 0
|
var key: Int = 0
|
||||||
|
var title: Int = 0
|
||||||
|
var description: Int = 0
|
||||||
|
|
||||||
init {
|
init {
|
||||||
context.withStyledAttributes(
|
context.withStyledAttributes(
|
||||||
|
@ -31,6 +37,9 @@ class OnboardingRadioButton(
|
||||||
0, 0
|
0, 0
|
||||||
) {
|
) {
|
||||||
key = getResourceId(R.styleable.OnboardingRadioButton_onboardingKey, 0)
|
key = getResourceId(R.styleable.OnboardingRadioButton_onboardingKey, 0)
|
||||||
|
title = getResourceId(R.styleable.OnboardingRadioButton_onboardingKeyTitle, 0)
|
||||||
|
description =
|
||||||
|
getResourceId(R.styleable.OnboardingRadioButton_onboardingKeyDescription, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,6 +61,28 @@ class OnboardingRadioButton(
|
||||||
toggleRadioGroups()
|
toggleRadioGroups()
|
||||||
clickListener?.invoke()
|
clickListener?.invoke()
|
||||||
}
|
}
|
||||||
|
if (title != 0) {
|
||||||
|
setRadioButtonText(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setRadioButtonText(context: Context) {
|
||||||
|
val builder = SpannableStringBuilder()
|
||||||
|
|
||||||
|
val spannableTitle = SpannableString(resources.getString(title))
|
||||||
|
spannableTitle.setTextSize(context, TITLE_TEXT_SIZE)
|
||||||
|
spannableTitle.setTextColor(context, R.color.primary_state_list_text_color)
|
||||||
|
|
||||||
|
builder.append(spannableTitle)
|
||||||
|
|
||||||
|
if (description != 0) {
|
||||||
|
val spannableDescription = SpannableString(resources.getString(description))
|
||||||
|
spannableDescription.setTextSize(context, DESCRIPTION_TEXT_SIZE)
|
||||||
|
spannableDescription.setTextColor(context, R.color.secondary_state_list_text_color)
|
||||||
|
builder.append("\n")
|
||||||
|
builder.append(spannableDescription)
|
||||||
|
}
|
||||||
|
this.text = builder
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateRadioValue(isChecked: Boolean) {
|
override fun updateRadioValue(isChecked: Boolean) {
|
||||||
|
@ -69,4 +100,9 @@ class OnboardingRadioButton(
|
||||||
radioGroups.uncheckAll()
|
radioGroups.uncheckAll()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TITLE_TEXT_SIZE = 16
|
||||||
|
private const val DESCRIPTION_TEXT_SIZE = 14
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,8 @@ import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import android.os.BatteryManager
|
import android.os.BatteryManager
|
||||||
|
import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.fenix.onboarding.FenixOnboarding
|
import org.mozilla.fenix.onboarding.FenixOnboarding
|
||||||
import org.mozilla.fenix.utils.Settings
|
|
||||||
import android.provider.Settings as AndroidSettings
|
import android.provider.Settings as AndroidSettings
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -67,13 +67,13 @@ object Performance {
|
||||||
* Disables the tracking protection popup. However, TP is still on.
|
* Disables the tracking protection popup. However, TP is still on.
|
||||||
*/
|
*/
|
||||||
private fun disableTrackingProtectionPopups(context: Context) {
|
private fun disableTrackingProtectionPopups(context: Context) {
|
||||||
Settings.getInstance(context).isOverrideTPPopupsForPerformanceTest = true
|
context.components.settings.isOverrideTPPopupsForPerformanceTest = true
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disables the first time PWA popup.
|
* Disables the first time PWA popup.
|
||||||
*/
|
*/
|
||||||
private fun disableFirstTimePWAPopup(context: Context) {
|
private fun disableFirstTimePWAPopup(context: Context) {
|
||||||
Settings.getInstance(context).userKnowsAboutPwas = true
|
context.components.settings.userKnowsAboutPwas = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ package org.mozilla.fenix.push
|
||||||
|
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.MainScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import mozilla.components.concept.engine.Engine
|
import mozilla.components.concept.engine.Engine
|
||||||
import mozilla.components.concept.engine.webpush.WebPushDelegate
|
import mozilla.components.concept.engine.webpush.WebPushDelegate
|
||||||
|
@ -22,7 +22,8 @@ import mozilla.components.support.base.log.logger.Logger
|
||||||
*/
|
*/
|
||||||
class WebPushEngineIntegration(
|
class WebPushEngineIntegration(
|
||||||
private val engine: Engine,
|
private val engine: Engine,
|
||||||
private val pushFeature: AutoPushFeature
|
private val pushFeature: AutoPushFeature,
|
||||||
|
private val coroutineScope: CoroutineScope = MainScope()
|
||||||
) : AutoPushFeature.Observer {
|
) : AutoPushFeature.Observer {
|
||||||
|
|
||||||
private var handler: WebPushHandler? = null
|
private var handler: WebPushHandler? = null
|
||||||
|
@ -39,13 +40,13 @@ class WebPushEngineIntegration(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMessageReceived(scope: PushScope, message: ByteArray?) {
|
override fun onMessageReceived(scope: PushScope, message: ByteArray?) {
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
coroutineScope.launch {
|
||||||
handler?.onPushMessage(scope, message)
|
handler?.onPushMessage(scope, message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSubscriptionChanged(scope: PushScope) {
|
override fun onSubscriptionChanged(scope: PushScope) {
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
coroutineScope.launch {
|
||||||
handler?.onSubscriptionChanged(scope)
|
handler?.onSubscriptionChanged(scope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
/* 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.search.awesomebar
|
||||||
|
|
||||||
|
import mozilla.components.browser.search.SearchEngine
|
||||||
|
import mozilla.components.browser.session.Session
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for the AwesomeBarView Interactor. This interface is implemented by objects that want
|
||||||
|
* to respond to user interaction on the AwesomebarView
|
||||||
|
*/
|
||||||
|
interface AwesomeBarInteractor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called whenever a suggestion containing a URL is tapped
|
||||||
|
* @param url the url the suggestion was providing
|
||||||
|
*/
|
||||||
|
fun onUrlTapped(url: String)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called whenever a search engine suggestion is tapped
|
||||||
|
* @param searchTerms the query contained by the search suggestion
|
||||||
|
*/
|
||||||
|
fun onSearchTermsTapped(searchTerms: String)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called whenever a search engine shortcut is tapped
|
||||||
|
* @param searchEngine the searchEngine that was selected
|
||||||
|
*/
|
||||||
|
fun onSearchShortcutEngineSelected(searchEngine: SearchEngine)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called whenever the "Search Engine Settings" item is tapped
|
||||||
|
*/
|
||||||
|
fun onClickSearchEngineSettings()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called whenever an existing session is selected from the sessionSuggestionProvider
|
||||||
|
*/
|
||||||
|
fun onExistingSessionSelected(session: Session)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called whenever an existing session is selected from the sessionSuggestionProvider
|
||||||
|
*/
|
||||||
|
fun onExistingSessionSelected(tabId: String)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called whenever the Shortcuts button is clicked
|
||||||
|
*/
|
||||||
|
fun onSearchShortcutsButtonClicked()
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ import mozilla.components.concept.awesomebar.AwesomeBar
|
||||||
import mozilla.components.concept.engine.EngineSession
|
import mozilla.components.concept.engine.EngineSession
|
||||||
import mozilla.components.feature.awesomebar.provider.BookmarksStorageSuggestionProvider
|
import mozilla.components.feature.awesomebar.provider.BookmarksStorageSuggestionProvider
|
||||||
import mozilla.components.feature.awesomebar.provider.HistoryStorageSuggestionProvider
|
import mozilla.components.feature.awesomebar.provider.HistoryStorageSuggestionProvider
|
||||||
|
import mozilla.components.feature.awesomebar.provider.SearchActionProvider
|
||||||
import mozilla.components.feature.awesomebar.provider.SearchSuggestionProvider
|
import mozilla.components.feature.awesomebar.provider.SearchSuggestionProvider
|
||||||
import mozilla.components.feature.awesomebar.provider.SessionSuggestionProvider
|
import mozilla.components.feature.awesomebar.provider.SessionSuggestionProvider
|
||||||
import mozilla.components.feature.search.SearchUseCases
|
import mozilla.components.feature.search.SearchUseCases
|
||||||
|
@ -29,51 +30,6 @@ import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.fenix.search.SearchEngineSource
|
import org.mozilla.fenix.search.SearchEngineSource
|
||||||
import org.mozilla.fenix.search.SearchFragmentState
|
import org.mozilla.fenix.search.SearchFragmentState
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface for the AwesomeBarView Interactor. This interface is implemented by objects that want
|
|
||||||
* to respond to user interaction on the AwesomebarView
|
|
||||||
*/
|
|
||||||
interface AwesomeBarInteractor {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called whenever a suggestion containing a URL is tapped
|
|
||||||
* @param url the url the suggestion was providing
|
|
||||||
*/
|
|
||||||
fun onUrlTapped(url: String)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called whenever a search engine suggestion is tapped
|
|
||||||
* @param searchTerms the query contained by the search suggestion
|
|
||||||
*/
|
|
||||||
fun onSearchTermsTapped(searchTerms: String)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called whenever a search engine shortcut is tapped
|
|
||||||
* @param searchEngine the searchEngine that was selected
|
|
||||||
*/
|
|
||||||
fun onSearchShortcutEngineSelected(searchEngine: SearchEngine)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called whenever the "Search Engine Settings" item is tapped
|
|
||||||
*/
|
|
||||||
fun onClickSearchEngineSettings()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called whenever an existing session is selected from the sessionSuggestionProvider
|
|
||||||
*/
|
|
||||||
fun onExistingSessionSelected(session: Session)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called whenever an existing session is selected from the sessionSuggestionProvider
|
|
||||||
*/
|
|
||||||
fun onExistingSessionSelected(tabId: String)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called whenever the Shortcuts button is clicked
|
|
||||||
*/
|
|
||||||
fun onSearchShortcutsButtonClicked()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* View that contains and configures the BrowserAwesomeBar
|
* View that contains and configures the BrowserAwesomeBar
|
||||||
*/
|
*/
|
||||||
|
@ -88,7 +44,8 @@ class AwesomeBarView(
|
||||||
private val shortcutsEnginePickerProvider: ShortcutsSuggestionProvider
|
private val shortcutsEnginePickerProvider: ShortcutsSuggestionProvider
|
||||||
private val bookmarksStorageSuggestionProvider: BookmarksStorageSuggestionProvider
|
private val bookmarksStorageSuggestionProvider: BookmarksStorageSuggestionProvider
|
||||||
private val defaultSearchSuggestionProvider: SearchSuggestionProvider
|
private val defaultSearchSuggestionProvider: SearchSuggestionProvider
|
||||||
private val searchSuggestionProviderMap: MutableMap<SearchEngine, SearchSuggestionProvider>
|
private val defaultSearchActionProvider: SearchActionProvider
|
||||||
|
private val searchSuggestionProviderMap: MutableMap<SearchEngine, List<AwesomeBar.SuggestionProvider>>
|
||||||
private var providersInUse = mutableSetOf<AwesomeBar.SuggestionProvider>()
|
private var providersInUse = mutableSetOf<AwesomeBar.SuggestionProvider>()
|
||||||
|
|
||||||
private val loadUrlUseCase = object : SessionUseCases.LoadUrlUseCase {
|
private val loadUrlUseCase = object : SessionUseCases.LoadUrlUseCase {
|
||||||
|
@ -141,7 +98,8 @@ class AwesomeBarView(
|
||||||
val draw = getDrawable(context, R.drawable.ic_link)!!
|
val draw = getDrawable(context, R.drawable.ic_link)!!
|
||||||
draw.colorFilter = createBlendModeColorFilterCompat(primaryTextColor, SRC_IN)
|
draw.colorFilter = createBlendModeColorFilterCompat(primaryTextColor, SRC_IN)
|
||||||
|
|
||||||
val engineForSpeculativeConnects = if (!isBrowsingModePrivate()) components.core.engine else null
|
val engineForSpeculativeConnects =
|
||||||
|
if (!isBrowsingModePrivate()) components.core.engine else null
|
||||||
sessionProvider =
|
sessionProvider =
|
||||||
SessionSuggestionProvider(
|
SessionSuggestionProvider(
|
||||||
context.resources,
|
context.resources,
|
||||||
|
@ -167,8 +125,9 @@ class AwesomeBarView(
|
||||||
engineForSpeculativeConnects
|
engineForSpeculativeConnects
|
||||||
)
|
)
|
||||||
|
|
||||||
val searchDrawable = getDrawable(context, R.drawable.ic_search)!!
|
val searchBitmap = getDrawable(context, R.drawable.ic_search)!!.apply {
|
||||||
searchDrawable.colorFilter = createBlendModeColorFilterCompat(primaryTextColor, SRC_IN)
|
colorFilter = createBlendModeColorFilterCompat(primaryTextColor, SRC_IN)
|
||||||
|
}.toBitmap()
|
||||||
|
|
||||||
defaultSearchSuggestionProvider =
|
defaultSearchSuggestionProvider =
|
||||||
SearchSuggestionProvider(
|
SearchSuggestionProvider(
|
||||||
|
@ -178,9 +137,20 @@ class AwesomeBarView(
|
||||||
fetchClient = components.core.client,
|
fetchClient = components.core.client,
|
||||||
mode = SearchSuggestionProvider.Mode.MULTIPLE_SUGGESTIONS,
|
mode = SearchSuggestionProvider.Mode.MULTIPLE_SUGGESTIONS,
|
||||||
limit = 3,
|
limit = 3,
|
||||||
icon = searchDrawable.toBitmap(),
|
icon = searchBitmap,
|
||||||
showDescription = false,
|
showDescription = false,
|
||||||
engine = engineForSpeculativeConnects
|
engine = engineForSpeculativeConnects,
|
||||||
|
filterExactMatch = true
|
||||||
|
)
|
||||||
|
|
||||||
|
defaultSearchActionProvider =
|
||||||
|
SearchActionProvider(
|
||||||
|
searchEngineGetter = suspend {
|
||||||
|
components.search.searchEngineManager.getDefaultSearchEngineAsync(context)
|
||||||
|
},
|
||||||
|
searchUseCase = searchUseCase,
|
||||||
|
icon = searchBitmap,
|
||||||
|
showDescription = false
|
||||||
)
|
)
|
||||||
|
|
||||||
shortcutsEnginePickerProvider =
|
shortcutsEnginePickerProvider =
|
||||||
|
@ -248,9 +218,7 @@ class AwesomeBarView(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.showSearchSuggestions) {
|
if (state.showSearchSuggestions) {
|
||||||
getSelectedSearchSuggestionProvider(state)?.let {
|
providersToAdd.addAll(getSelectedSearchSuggestionProvider(state))
|
||||||
providersToAdd.add(it)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isBrowsingModePrivate()) {
|
if (!isBrowsingModePrivate()) {
|
||||||
|
@ -274,9 +242,7 @@ class AwesomeBarView(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!state.showSearchSuggestions) {
|
if (!state.showSearchSuggestions) {
|
||||||
getSelectedSearchSuggestionProvider(state)?.let {
|
providersToRemove.addAll(getSelectedSearchSuggestionProvider(state))
|
||||||
providersToRemove.add(it)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isBrowsingModePrivate()) {
|
if (isBrowsingModePrivate()) {
|
||||||
|
@ -291,9 +257,12 @@ class AwesomeBarView(
|
||||||
?: false
|
?: false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getSelectedSearchSuggestionProvider(state: SearchFragmentState): SearchSuggestionProvider? {
|
private fun getSelectedSearchSuggestionProvider(state: SearchFragmentState): List<AwesomeBar.SuggestionProvider> {
|
||||||
return when (state.searchEngineSource) {
|
return when (state.searchEngineSource) {
|
||||||
is SearchEngineSource.Default -> defaultSearchSuggestionProvider
|
is SearchEngineSource.Default -> listOf(
|
||||||
|
defaultSearchActionProvider,
|
||||||
|
defaultSearchSuggestionProvider
|
||||||
|
)
|
||||||
is SearchEngineSource.Shortcut -> getSuggestionProviderForEngine(
|
is SearchEngineSource.Shortcut -> getSuggestionProviderForEngine(
|
||||||
state.searchEngineSource.searchEngine
|
state.searchEngineSource.searchEngine
|
||||||
)
|
)
|
||||||
|
@ -307,26 +276,38 @@ class AwesomeBarView(
|
||||||
view.addProviders(shortcutsEnginePickerProvider)
|
view.addProviders(shortcutsEnginePickerProvider)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getSuggestionProviderForEngine(engine: SearchEngine): SearchSuggestionProvider? {
|
private fun getSuggestionProviderForEngine(engine: SearchEngine): List<AwesomeBar.SuggestionProvider> {
|
||||||
return searchSuggestionProviderMap.getOrPut(engine) {
|
return searchSuggestionProviderMap.getOrPut(engine) {
|
||||||
val context = container.context
|
val context = container.context
|
||||||
val components = context.components
|
val components = context.components
|
||||||
val primaryTextColor = context.getColorFromAttr(R.attr.primaryText)
|
val primaryTextColor = context.getColorFromAttr(R.attr.primaryText)
|
||||||
|
|
||||||
val draw = getDrawable(context, R.drawable.ic_search)
|
val searchBitmap = getDrawable(context, R.drawable.ic_search)?.apply {
|
||||||
draw?.colorFilter = createBlendModeColorFilterCompat(primaryTextColor, SRC_IN)
|
colorFilter = createBlendModeColorFilterCompat(primaryTextColor, SRC_IN)
|
||||||
|
}?.toBitmap()
|
||||||
|
|
||||||
val engineForSpeculativeConnects = if (!isBrowsingModePrivate()) components.core.engine else null
|
val engineForSpeculativeConnects =
|
||||||
|
if (!isBrowsingModePrivate()) components.core.engine else null
|
||||||
SearchSuggestionProvider(
|
val searchEngine =
|
||||||
components.search.provider.installedSearchEngines(context).list.find { it.name == engine.name }
|
components.search.provider.installedSearchEngines(context).list.find { it.name == engine.name }
|
||||||
?: components.search.provider.getDefaultEngine(context),
|
?: components.search.provider.getDefaultEngine(context)
|
||||||
shortcutSearchUseCase,
|
|
||||||
components.core.client,
|
listOf(
|
||||||
limit = 3,
|
SearchActionProvider(
|
||||||
mode = SearchSuggestionProvider.Mode.MULTIPLE_SUGGESTIONS,
|
searchEngineGetter = suspend { searchEngine },
|
||||||
icon = draw?.toBitmap(),
|
searchUseCase = shortcutSearchUseCase,
|
||||||
engine = engineForSpeculativeConnects
|
icon = searchBitmap
|
||||||
|
),
|
||||||
|
SearchSuggestionProvider(
|
||||||
|
searchEngine,
|
||||||
|
shortcutSearchUseCase,
|
||||||
|
components.core.client,
|
||||||
|
limit = 3,
|
||||||
|
mode = SearchSuggestionProvider.Mode.MULTIPLE_SUGGESTIONS,
|
||||||
|
icon = searchBitmap,
|
||||||
|
engine = engineForSpeculativeConnects,
|
||||||
|
filterExactMatch = true
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ package org.mozilla.fenix.search.toolbar
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.drawable.BitmapDrawable
|
import android.graphics.drawable.BitmapDrawable
|
||||||
|
import androidx.annotation.VisibleForTesting
|
||||||
import androidx.appcompat.content.res.AppCompatResources
|
import androidx.appcompat.content.res.AppCompatResources
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import mozilla.components.browser.domains.autocomplete.ShippedDomainsProvider
|
import mozilla.components.browser.domains.autocomplete.ShippedDomainsProvider
|
||||||
|
@ -56,7 +57,8 @@ class ToolbarView(
|
||||||
engine: Engine
|
engine: Engine
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private var isInitialized = false
|
@VisibleForTesting
|
||||||
|
internal var isInitialized = false
|
||||||
|
|
||||||
init {
|
init {
|
||||||
view.apply {
|
view.apply {
|
||||||
|
|
|
@ -37,7 +37,6 @@ import org.mozilla.fenix.IntentReceiverActivity
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.ext.components
|
import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.fenix.settings.PhoneFeature
|
import org.mozilla.fenix.settings.PhoneFeature
|
||||||
import org.mozilla.fenix.utils.Settings
|
|
||||||
import com.google.android.material.R as MaterialR
|
import com.google.android.material.R as MaterialR
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -62,6 +61,7 @@ class QuickSettingsSheetDialogFragment : AppCompatDialogFragment() {
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View {
|
): View {
|
||||||
val context = requireContext()
|
val context = requireContext()
|
||||||
|
val components = context.components
|
||||||
val rootView = inflateRootView(container)
|
val rootView = inflateRootView(container)
|
||||||
|
|
||||||
quickSettingsStore = QuickSettingsFragmentStore.createStore(
|
quickSettingsStore = QuickSettingsFragmentStore.createStore(
|
||||||
|
@ -70,7 +70,7 @@ class QuickSettingsSheetDialogFragment : AppCompatDialogFragment() {
|
||||||
websiteTitle = args.title,
|
websiteTitle = args.title,
|
||||||
isSecured = args.isSecured,
|
isSecured = args.isSecured,
|
||||||
permissions = args.sitePermissions,
|
permissions = args.sitePermissions,
|
||||||
settings = Settings.getInstance(context),
|
settings = components.settings,
|
||||||
certificateName = args.certificateName
|
certificateName = args.certificateName
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -79,12 +79,12 @@ class QuickSettingsSheetDialogFragment : AppCompatDialogFragment() {
|
||||||
quickSettingsStore = quickSettingsStore,
|
quickSettingsStore = quickSettingsStore,
|
||||||
ioScope = viewLifecycleOwner.lifecycleScope + Dispatchers.IO,
|
ioScope = viewLifecycleOwner.lifecycleScope + Dispatchers.IO,
|
||||||
navController = findNavController(),
|
navController = findNavController(),
|
||||||
session = context.components.core.sessionManager.findSessionById(args.sessionId),
|
session = components.core.sessionManager.findSessionById(args.sessionId),
|
||||||
sitePermissions = args.sitePermissions,
|
sitePermissions = args.sitePermissions,
|
||||||
settings = Settings.getInstance(context),
|
settings = components.settings,
|
||||||
permissionStorage = context.components.core.permissionStorage,
|
permissionStorage = components.core.permissionStorage,
|
||||||
reload = context.components.useCases.sessionUseCases.reload,
|
reload = components.useCases.sessionUseCases.reload,
|
||||||
addNewTab = context.components.useCases.tabsUseCases.addTab,
|
addNewTab = components.useCases.tabsUseCases.addTab,
|
||||||
requestRuntimePermissions = { permissions ->
|
requestRuntimePermissions = { permissions ->
|
||||||
requestPermissions(permissions, REQUEST_CODE_QUICK_SETTINGS_PERMISSIONS)
|
requestPermissions(permissions, REQUEST_CODE_QUICK_SETTINGS_PERMISSIONS)
|
||||||
tryToRequestPermissions = true
|
tryToRequestPermissions = true
|
||||||
|
|
|
@ -16,8 +16,10 @@ import androidx.lifecycle.LifecycleCoroutineScope
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
import com.google.android.material.tabs.TabLayout
|
import com.google.android.material.tabs.TabLayout
|
||||||
import kotlinx.android.extensions.LayoutContainer
|
import kotlinx.android.extensions.LayoutContainer
|
||||||
|
import kotlinx.android.synthetic.main.component_tabstray.*
|
||||||
import kotlinx.android.synthetic.main.component_tabstray.view.*
|
import kotlinx.android.synthetic.main.component_tabstray.view.*
|
||||||
import kotlinx.android.synthetic.main.component_tabstray_fab.view.*
|
import kotlinx.android.synthetic.main.component_tabstray_fab.view.*
|
||||||
|
import kotlinx.android.synthetic.main.tabs_tray_tab_counter.*
|
||||||
import kotlinx.coroutines.Dispatchers.Main
|
import kotlinx.coroutines.Dispatchers.Main
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
@ -36,7 +38,7 @@ import org.mozilla.fenix.ext.settings
|
||||||
/**
|
/**
|
||||||
* View that contains and configures the BrowserAwesomeBar
|
* View that contains and configures the BrowserAwesomeBar
|
||||||
*/
|
*/
|
||||||
@Suppress("LongParameterList")
|
@Suppress("LongParameterList", "TooManyFunctions", "LargeClass")
|
||||||
class TabTrayView(
|
class TabTrayView(
|
||||||
private val container: ViewGroup,
|
private val container: ViewGroup,
|
||||||
private val interactor: TabTrayInteractor,
|
private val interactor: TabTrayInteractor,
|
||||||
|
@ -245,6 +247,17 @@ class TabTrayView(
|
||||||
View.VISIBLE
|
View.VISIBLE
|
||||||
}
|
}
|
||||||
view.tab_tray_overflow.isVisible = !hasNoTabs
|
view.tab_tray_overflow.isVisible = !hasNoTabs
|
||||||
|
|
||||||
|
counter_text.text = "${state.normalTabs.size}"
|
||||||
|
updateTabCounterContentDescription(state.normalTabs.size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateTabCounterContentDescription(count: Int) {
|
||||||
|
view.tab_layout.getTabAt(0)?.contentDescription = if (count == 1) {
|
||||||
|
view.context?.getString(R.string.open_tab_tray_single)
|
||||||
|
} else {
|
||||||
|
view.context?.getString(R.string.open_tab_tray_plural, count.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,11 +7,11 @@ package org.mozilla.fenix.tabtray
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.accessibility.AccessibilityNodeInfo
|
import android.view.accessibility.AccessibilityNodeInfo
|
||||||
import android.widget.ImageButton
|
import android.widget.ImageButton
|
||||||
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.annotation.VisibleForTesting
|
import androidx.annotation.VisibleForTesting
|
||||||
import androidx.appcompat.widget.AppCompatImageButton
|
import androidx.appcompat.widget.AppCompatImageButton
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.doOnNextLayout
|
|
||||||
import mozilla.components.browser.state.state.MediaState
|
import mozilla.components.browser.state.state.MediaState
|
||||||
import mozilla.components.browser.tabstray.TabViewHolder
|
import mozilla.components.browser.tabstray.TabViewHolder
|
||||||
import mozilla.components.browser.tabstray.thumbnail.TabThumbnailView
|
import mozilla.components.browser.tabstray.thumbnail.TabThumbnailView
|
||||||
|
@ -21,7 +21,7 @@ import mozilla.components.concept.tabstray.TabsTray
|
||||||
import mozilla.components.feature.media.ext.pauseIfPlaying
|
import mozilla.components.feature.media.ext.pauseIfPlaying
|
||||||
import mozilla.components.feature.media.ext.playIfPaused
|
import mozilla.components.feature.media.ext.playIfPaused
|
||||||
import mozilla.components.support.base.observer.Observable
|
import mozilla.components.support.base.observer.Observable
|
||||||
import mozilla.components.support.images.ext.loadIntoView
|
import mozilla.components.support.images.ImageLoadRequest
|
||||||
import mozilla.components.support.images.loader.ImageLoader
|
import mozilla.components.support.images.loader.ImageLoader
|
||||||
import mozilla.components.support.ktx.kotlin.tryGetHostFromUrl
|
import mozilla.components.support.ktx.kotlin.tryGetHostFromUrl
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
|
@ -32,6 +32,7 @@ import org.mozilla.fenix.ext.removeAndDisable
|
||||||
import org.mozilla.fenix.ext.removeTouchDelegate
|
import org.mozilla.fenix.ext.removeTouchDelegate
|
||||||
import org.mozilla.fenix.ext.showAndEnable
|
import org.mozilla.fenix.ext.showAndEnable
|
||||||
import org.mozilla.fenix.ext.toTab
|
import org.mozilla.fenix.ext.toTab
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A RecyclerView ViewHolder implementation for "tab" items.
|
* A RecyclerView ViewHolder implementation for "tab" items.
|
||||||
|
@ -73,10 +74,7 @@ class TabTrayViewHolder(
|
||||||
if (tab.thumbnail != null) {
|
if (tab.thumbnail != null) {
|
||||||
thumbnailView.setImageBitmap(tab.thumbnail)
|
thumbnailView.setImageBitmap(tab.thumbnail)
|
||||||
} else {
|
} else {
|
||||||
// Make sure we have the view's dimensions so we can load the image at the correct size
|
loadIntoThumbnailView(thumbnailView, tab.id)
|
||||||
thumbnailView.doOnNextLayout {
|
|
||||||
imageLoader.loadIntoView(thumbnailView, tab.id)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Media state
|
// Media state
|
||||||
|
@ -182,6 +180,14 @@ class TabTrayViewHolder(
|
||||||
closeView.context.getString(R.string.close_tab_title, title)
|
closeView.context.getString(R.string.close_tab_title, title)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun loadIntoThumbnailView(thumbnailView: ImageView, id: String) {
|
||||||
|
val thumbnailSize = max(
|
||||||
|
itemView.resources.getDimensionPixelSize(R.dimen.tab_tray_thumbnail_height),
|
||||||
|
itemView.resources.getDimensionPixelSize(R.dimen.tab_tray_thumbnail_width)
|
||||||
|
)
|
||||||
|
imageLoader.loadIntoView(thumbnailView, ImageLoadRequest(id, thumbnailSize))
|
||||||
|
}
|
||||||
|
|
||||||
internal fun updateAccessibilityRowIndex(item: View, newIndex: Int) {
|
internal fun updateAccessibilityRowIndex(item: View, newIndex: Int) {
|
||||||
item.setAccessibilityDelegate(object : View.AccessibilityDelegate() {
|
item.setAccessibilityDelegate(object : View.AccessibilityDelegate() {
|
||||||
override fun onInitializeAccessibilityNodeInfo(
|
override fun onInitializeAccessibilityNodeInfo(
|
||||||
|
|
|
@ -21,7 +21,7 @@ import kotlinx.android.synthetic.main.tracking_protection_onboarding_popup.view.
|
||||||
import mozilla.components.browser.session.Session
|
import mozilla.components.browser.session.Session
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
import org.mozilla.fenix.ext.components
|
import org.mozilla.fenix.components.metrics.MetricController
|
||||||
import org.mozilla.fenix.ext.increaseTapArea
|
import org.mozilla.fenix.ext.increaseTapArea
|
||||||
import org.mozilla.fenix.utils.Settings
|
import org.mozilla.fenix.utils.Settings
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ import org.mozilla.fenix.utils.Settings
|
||||||
class TrackingProtectionOverlay(
|
class TrackingProtectionOverlay(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val settings: Settings,
|
private val settings: Settings,
|
||||||
|
private val metrics: MetricController,
|
||||||
private val getToolbar: () -> View
|
private val getToolbar: () -> View
|
||||||
) : Session.Observer {
|
) : Session.Observer {
|
||||||
|
|
||||||
|
@ -54,7 +55,7 @@ class TrackingProtectionOverlay(
|
||||||
override fun onTouchEvent(event: MotionEvent): Boolean {
|
override fun onTouchEvent(event: MotionEvent): Boolean {
|
||||||
|
|
||||||
if (event.action == MotionEvent.ACTION_DOWN) {
|
if (event.action == MotionEvent.ACTION_DOWN) {
|
||||||
context.components.analytics.metrics.track(Event.ContextualHintETPOutsideTap)
|
metrics.track(Event.ContextualHintETPOutsideTap)
|
||||||
}
|
}
|
||||||
return super.onTouchEvent(event)
|
return super.onTouchEvent(event)
|
||||||
}
|
}
|
||||||
|
@ -62,7 +63,7 @@ class TrackingProtectionOverlay(
|
||||||
|
|
||||||
val layout = LayoutInflater.from(context)
|
val layout = LayoutInflater.from(context)
|
||||||
.inflate(R.layout.tracking_protection_onboarding_popup, null)
|
.inflate(R.layout.tracking_protection_onboarding_popup, null)
|
||||||
val isBottomToolbar = Settings.getInstance(context).shouldUseBottomToolbar
|
val isBottomToolbar = settings.shouldUseBottomToolbar
|
||||||
|
|
||||||
layout.drop_down_triangle.isGone = isBottomToolbar
|
layout.drop_down_triangle.isGone = isBottomToolbar
|
||||||
layout.pop_up_triangle.isVisible = isBottomToolbar
|
layout.pop_up_triangle.isVisible = isBottomToolbar
|
||||||
|
@ -76,13 +77,13 @@ class TrackingProtectionOverlay(
|
||||||
val closeButton = layout.findViewById<ImageView>(R.id.close_onboarding)
|
val closeButton = layout.findViewById<ImageView>(R.id.close_onboarding)
|
||||||
closeButton.increaseTapArea(BUTTON_INCREASE_DPS)
|
closeButton.increaseTapArea(BUTTON_INCREASE_DPS)
|
||||||
closeButton.setOnClickListener {
|
closeButton.setOnClickListener {
|
||||||
context.components.analytics.metrics.track(Event.ContextualHintETPDismissed)
|
metrics.track(Event.ContextualHintETPDismissed)
|
||||||
trackingOnboardingDialog.dismiss()
|
trackingOnboardingDialog.dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
val res = context.resources
|
val res = context.resources
|
||||||
val triangleWidthPx = res.getDimension(R.dimen.tp_onboarding_triangle_height)
|
val triangleWidthPx = res.getDimension(R.dimen.cfr_triangle_height)
|
||||||
val triangleMarginStartPx = res.getDimension(R.dimen.tp_onboarding_triangle_margin_start)
|
val triangleMarginStartPx = res.getDimension(R.dimen.cfr_triangle_margin_edge)
|
||||||
|
|
||||||
val toolbar = getToolbar()
|
val toolbar = getToolbar()
|
||||||
val trackingProtectionIcon: View =
|
val trackingProtectionIcon: View =
|
||||||
|
@ -115,12 +116,12 @@ class TrackingProtectionOverlay(
|
||||||
val etpShield =
|
val etpShield =
|
||||||
getToolbar().findViewById<View>(R.id.mozac_browser_toolbar_tracking_protection_indicator)
|
getToolbar().findViewById<View>(R.id.mozac_browser_toolbar_tracking_protection_indicator)
|
||||||
trackingOnboardingDialog.message.setOnClickListener {
|
trackingOnboardingDialog.message.setOnClickListener {
|
||||||
context.components.analytics.metrics.track(Event.ContextualHintETPInsideTap)
|
metrics.track(Event.ContextualHintETPInsideTap)
|
||||||
trackingOnboardingDialog.dismiss()
|
trackingOnboardingDialog.dismiss()
|
||||||
etpShield.performClick()
|
etpShield.performClick()
|
||||||
}
|
}
|
||||||
|
|
||||||
context.components.analytics.metrics.track(Event.ContextualHintETPDisplayed)
|
metrics.track(Event.ContextualHintETPDisplayed)
|
||||||
trackingOnboardingDialog.show()
|
trackingOnboardingDialog.show()
|
||||||
settings.incrementTrackingProtectionOnboardingCount()
|
settings.incrementTrackingProtectionOnboardingCount()
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,9 +33,9 @@ import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.fenix.ext.getPreferenceKey
|
import org.mozilla.fenix.ext.getPreferenceKey
|
||||||
import org.mozilla.fenix.settings.PhoneFeature
|
import org.mozilla.fenix.settings.PhoneFeature
|
||||||
import org.mozilla.fenix.settings.deletebrowsingdata.DeleteBrowsingDataOnQuitType
|
import org.mozilla.fenix.settings.deletebrowsingdata.DeleteBrowsingDataOnQuitType
|
||||||
import org.mozilla.fenix.settings.logins.fragment.SavedLoginsFragment
|
|
||||||
import org.mozilla.fenix.settings.logins.SavedLoginsSortingStrategyMenu
|
import org.mozilla.fenix.settings.logins.SavedLoginsSortingStrategyMenu
|
||||||
import org.mozilla.fenix.settings.logins.SortingStrategy
|
import org.mozilla.fenix.settings.logins.SortingStrategy
|
||||||
|
import org.mozilla.fenix.settings.logins.fragment.SavedLoginsFragment
|
||||||
import org.mozilla.fenix.settings.registerOnSharedPreferenceChangeListener
|
import org.mozilla.fenix.settings.registerOnSharedPreferenceChangeListener
|
||||||
import java.security.InvalidParameterException
|
import java.security.InvalidParameterException
|
||||||
|
|
||||||
|
@ -43,12 +43,11 @@ private const val AUTOPLAY_USER_SETTING = "AUTOPLAY_USER_SETTING"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple wrapper for SharedPreferences that makes reading preference a little bit easier.
|
* A simple wrapper for SharedPreferences that makes reading preference a little bit easier.
|
||||||
|
* @param appContext Reference to application context.
|
||||||
*/
|
*/
|
||||||
@Suppress("LargeClass", "TooManyFunctions")
|
@Suppress("LargeClass", "TooManyFunctions")
|
||||||
class Settings private constructor(
|
class Settings(private val appContext: Context) : PreferencesHolder {
|
||||||
context: Context,
|
|
||||||
private val isCrashReportEnabledInBuild: Boolean
|
|
||||||
) : PreferencesHolder {
|
|
||||||
companion object {
|
companion object {
|
||||||
const val showLoginsSecureWarningSyncMaxCount = 1
|
const val showLoginsSecureWarningSyncMaxCount = 1
|
||||||
const val showLoginsSecureWarningMaxCount = 1
|
const val showLoginsSecureWarningMaxCount = 1
|
||||||
|
@ -88,24 +87,11 @@ class Settings private constructor(
|
||||||
ASK_TO_ALLOW_INT -> AutoplayAction.BLOCKED
|
ASK_TO_ALLOW_INT -> AutoplayAction.BLOCKED
|
||||||
else -> throw InvalidParameterException("$this is not a valid SitePermissionsRules.AutoplayAction")
|
else -> throw InvalidParameterException("$this is not a valid SitePermissionsRules.AutoplayAction")
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
internal var instance: Settings? = null
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
@Synchronized
|
|
||||||
fun getInstance(
|
|
||||||
context: Context,
|
|
||||||
isCrashReportEnabledInBuild: Boolean = BuildConfig.CRASH_REPORTING && Config.channel.isReleased
|
|
||||||
): Settings {
|
|
||||||
if (instance == null) {
|
|
||||||
instance = Settings(context.applicationContext, isCrashReportEnabledInBuild)
|
|
||||||
}
|
|
||||||
return instance ?: throw AssertionError("Instance cleared")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val appContext = context.applicationContext
|
@VisibleForTesting
|
||||||
|
internal val isCrashReportEnabledInBuild: Boolean =
|
||||||
|
BuildConfig.CRASH_REPORTING && Config.channel.isReleased
|
||||||
|
|
||||||
override val preferences: SharedPreferences =
|
override val preferences: SharedPreferences =
|
||||||
appContext.getSharedPreferences(FENIX_PREFERENCES, MODE_PRIVATE)
|
appContext.getSharedPreferences(FENIX_PREFERENCES, MODE_PRIVATE)
|
||||||
|
@ -372,7 +358,7 @@ class Settings private constructor(
|
||||||
appContext.getPreferenceKey(R.string.pref_key_tracking_protection_standard_option),
|
appContext.getPreferenceKey(R.string.pref_key_tracking_protection_standard_option),
|
||||||
false
|
false
|
||||||
).apply()
|
).apply()
|
||||||
appContext?.components?.let {
|
appContext.components.let {
|
||||||
val policy = it.core.trackingProtectionPolicyFactory
|
val policy = it.core.trackingProtectionPolicyFactory
|
||||||
.createTrackingProtectionPolicy()
|
.createTrackingProtectionPolicy()
|
||||||
it.useCases.settingsUseCases.updateTrackingProtection.invoke(policy)
|
it.useCases.settingsUseCases.updateTrackingProtection.invoke(policy)
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||||
|
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:fromDegrees="45"
|
||||||
|
android:pivotX="-40%"
|
||||||
|
android:pivotY="87%"
|
||||||
|
android:toDegrees="45">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<stroke
|
||||||
|
android:width="10dp"
|
||||||
|
android:color="#FFFFFF" />
|
||||||
|
<solid android:color="#FFFFFF" />
|
||||||
|
</shape>
|
||||||
|
</rotate>
|
|
@ -1,20 +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>
|
|
||||||
<rotate
|
|
||||||
android:fromDegrees="45"
|
|
||||||
android:pivotX="-40%"
|
|
||||||
android:pivotY="87%"
|
|
||||||
android:toDegrees="45">
|
|
||||||
<shape android:shape="rectangle">
|
|
||||||
<stroke
|
|
||||||
android:width="10dp"
|
|
||||||
android:color="#7542E5" />
|
|
||||||
<solid android:color="#7542E5" />
|
|
||||||
</shape>
|
|
||||||
</rotate>
|
|
||||||
</item>
|
|
||||||
</layer-list>
|
|
|
@ -1,20 +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>
|
|
||||||
<rotate
|
|
||||||
android:fromDegrees="45"
|
|
||||||
android:pivotX="-40%"
|
|
||||||
android:pivotY="87%"
|
|
||||||
android:toDegrees="45">
|
|
||||||
<shape android:shape="rectangle">
|
|
||||||
<stroke
|
|
||||||
android:width="10dp"
|
|
||||||
android:color="#0250BB" />
|
|
||||||
<solid android:color="#0250BB" />
|
|
||||||
</shape>
|
|
||||||
</rotate>
|
|
||||||
</item>
|
|
||||||
</layer-list>
|
|
|
@ -46,27 +46,28 @@
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="80dp"
|
android:layout_height="80dp"
|
||||||
android:background="@color/foundation_normal_theme"
|
android:background="@color/foundation_normal_theme"
|
||||||
app:tabIndicatorColor="@color/accent_normal_theme"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:tabIconTint="@color/tab_icon"
|
|
||||||
app:tabRippleColor="@android:color/transparent"
|
|
||||||
app:tabGravity="fill"
|
|
||||||
app:layout_constraintWidth_percent="0.5"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/handle"
|
app:layout_constraintTop_toBottomOf="@+id/handle"
|
||||||
app:layout_constraintStart_toStartOf="parent">
|
app:layout_constraintWidth_percent="0.5"
|
||||||
|
app:tabGravity="fill"
|
||||||
|
app:tabIconTint="@color/tab_icon"
|
||||||
|
app:tabIndicatorColor="@color/accent_normal_theme"
|
||||||
|
app:tabRippleColor="@android:color/transparent">
|
||||||
|
|
||||||
<com.google.android.material.tabs.TabItem
|
<com.google.android.material.tabs.TabItem
|
||||||
android:id="@+id/default_tab_item"
|
android:id="@+id/default_tab_item"
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:icon="@drawable/ic_tabs"
|
android:layout_height="match_parent"
|
||||||
android:contentDescription="@string/tab_header_label" />
|
android:contentDescription="@string/tab_header_label"
|
||||||
|
android:layout="@layout/tabs_tray_tab_counter"
|
||||||
|
app:tabIconTint="@color/tab_icon" />
|
||||||
|
|
||||||
<com.google.android.material.tabs.TabItem
|
<com.google.android.material.tabs.TabItem
|
||||||
android:id="@+id/private_tab_item"
|
android:id="@+id/private_tab_item"
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:icon="@drawable/ic_private_browsing"
|
android:layout_height="match_parent"
|
||||||
android:contentDescription="@string/tabs_header_private_tabs_title" />
|
android:contentDescription="@string/tabs_header_private_tabs_title"
|
||||||
|
android:icon="@drawable/ic_private_browsing" />
|
||||||
|
|
||||||
</com.google.android.material.tabs.TabLayout>
|
</com.google.android.material.tabs.TabLayout>
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
android:button="@null"
|
android:button="@null"
|
||||||
app:drawableStartCompat="?android:attr/listChoiceIndicatorSingle"
|
app:drawableStartCompat="?android:attr/listChoiceIndicatorSingle"
|
||||||
android:drawablePadding="@dimen/preference_seek_bar_padding"
|
android:drawablePadding="@dimen/radio_button_preference_drawable_padding"
|
||||||
android:paddingTop="@dimen/radio_button_preference_vertical"
|
android:paddingTop="@dimen/radio_button_preference_vertical"
|
||||||
android:paddingStart="@dimen/radio_button_preference_horizontal"
|
android:paddingStart="@dimen/radio_button_preference_horizontal"
|
||||||
android:paddingEnd="@dimen/radio_button_preference_horizontal"
|
android:paddingEnd="@dimen/radio_button_preference_horizontal"
|
||||||
|
@ -40,7 +40,7 @@
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
android:button="@null"
|
android:button="@null"
|
||||||
app:drawableStartCompat="?android:attr/listChoiceIndicatorSingle"
|
app:drawableStartCompat="?android:attr/listChoiceIndicatorSingle"
|
||||||
android:drawablePadding="@dimen/preference_seek_bar_padding"
|
android:drawablePadding="@dimen/radio_button_preference_drawable_padding"
|
||||||
android:paddingTop="@dimen/radio_button_preference_vertical"
|
android:paddingTop="@dimen/radio_button_preference_vertical"
|
||||||
android:paddingStart="@dimen/radio_button_preference_horizontal"
|
android:paddingStart="@dimen/radio_button_preference_horizontal"
|
||||||
android:paddingEnd="@dimen/radio_button_preference_horizontal"
|
android:paddingEnd="@dimen/radio_button_preference_horizontal"
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
android:button="@null"
|
android:button="@null"
|
||||||
android:drawablePadding="@dimen/preference_seek_bar_padding"
|
android:drawablePadding="@dimen/radio_button_preference_drawable_padding"
|
||||||
android:paddingStart="@dimen/radio_button_preference_horizontal"
|
android:paddingStart="@dimen/radio_button_preference_horizontal"
|
||||||
android:paddingTop="@dimen/radio_button_preference_vertical"
|
android:paddingTop="@dimen/radio_button_preference_vertical"
|
||||||
android:paddingEnd="@dimen/radio_button_preference_horizontal"
|
android:paddingEnd="@dimen/radio_button_preference_horizontal"
|
||||||
|
@ -39,7 +39,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
android:button="@null"
|
android:button="@null"
|
||||||
android:drawablePadding="@dimen/preference_seek_bar_padding"
|
android:drawablePadding="@dimen/radio_button_preference_drawable_padding"
|
||||||
android:paddingStart="@dimen/radio_button_preference_horizontal"
|
android:paddingStart="@dimen/radio_button_preference_horizontal"
|
||||||
android:paddingTop="@dimen/radio_button_preference_vertical"
|
android:paddingTop="@dimen/radio_button_preference_vertical"
|
||||||
android:paddingEnd="@dimen/radio_button_preference_horizontal"
|
android:paddingEnd="@dimen/radio_button_preference_horizontal"
|
||||||
|
@ -54,7 +54,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
android:button="@null"
|
android:button="@null"
|
||||||
android:drawablePadding="@dimen/preference_seek_bar_padding"
|
android:drawablePadding="@dimen/radio_button_preference_drawable_padding"
|
||||||
android:paddingStart="@dimen/radio_button_preference_horizontal"
|
android:paddingStart="@dimen/radio_button_preference_horizontal"
|
||||||
android:paddingTop="@dimen/radio_button_preference_vertical"
|
android:paddingTop="@dimen/radio_button_preference_vertical"
|
||||||
android:paddingEnd="@dimen/radio_button_preference_horizontal"
|
android:paddingEnd="@dimen/radio_button_preference_horizontal"
|
||||||
|
@ -68,7 +68,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
android:button="@null"
|
android:button="@null"
|
||||||
android:drawablePadding="@dimen/preference_seek_bar_padding"
|
android:drawablePadding="@dimen/radio_button_preference_drawable_padding"
|
||||||
android:paddingStart="@dimen/radio_button_preference_horizontal"
|
android:paddingStart="@dimen/radio_button_preference_horizontal"
|
||||||
android:paddingTop="@dimen/radio_button_preference_vertical"
|
android:paddingTop="@dimen/radio_button_preference_vertical"
|
||||||
android:paddingEnd="@dimen/radio_button_preference_horizontal"
|
android:paddingEnd="@dimen/radio_button_preference_horizontal"
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/onboarding_card"
|
android:id="@+id/onboarding_card"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -140,34 +141,18 @@
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="16dp"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
android:contentDescription="@string/onboarding_theme_automatic_title"
|
android:contentDescription="@string/onboarding_theme_automatic_title"
|
||||||
|
android:foreground="@drawable/rounded_ripple"
|
||||||
android:paddingStart="0dp"
|
android:paddingStart="0dp"
|
||||||
android:paddingEnd="8dp"
|
android:paddingEnd="8dp"
|
||||||
android:theme="@style/Checkable.Colored"
|
android:theme="@style/Checkable.Colored"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/divider"
|
app:layout_constraintTop_toBottomOf="@+id/divider"
|
||||||
app:onboardingKey="@string/pref_key_follow_device_theme" />
|
app:onboardingKey="@string/pref_key_follow_device_theme"
|
||||||
|
app:onboardingKeyDescription="@string/onboarding_theme_automatic_summary"
|
||||||
|
app:onboardingKeyTitle="@string/onboarding_theme_automatic_title"
|
||||||
|
tools:text="Automatic" />
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/automatic_title"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="9dp"
|
|
||||||
android:text="@string/onboarding_theme_automatic_title"
|
|
||||||
android:textColor="?primaryText"
|
|
||||||
android:textSize="16sp"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/theme_automatic_radio_button"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/divider" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/automatic_theme_summary"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/onboarding_theme_automatic_summary"
|
|
||||||
android:textColor="?secondaryText"
|
|
||||||
android:textSize="14sp"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/theme_automatic_radio_button"
|
|
||||||
app:layout_constraintEnd_toEndOf="@id/clickable_region_automatic"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/automatic_title" />
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
|
@ -7,7 +7,9 @@
|
||||||
android:id="@+id/onboarding_card"
|
android:id="@+id/onboarding_card"
|
||||||
style="@style/OnboardingCardLightWithPadding"
|
style="@style/OnboardingCardLightWithPadding"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content"
|
||||||
|
android:clipChildren="false"
|
||||||
|
android:clipToPadding="false">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/header_text"
|
android:id="@+id/header_text"
|
||||||
|
@ -44,97 +46,48 @@
|
||||||
app:layout_constraintTop_toBottomOf="@id/header_text"
|
app:layout_constraintTop_toBottomOf="@id/header_text"
|
||||||
tools:text="@string/onboarding_tracking_protection_description_2" />
|
tools:text="@string/onboarding_tracking_protection_description_2" />
|
||||||
|
|
||||||
<View
|
|
||||||
android:id="@+id/clickable_region_standard"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:foreground="@drawable/rounded_ripple"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/protection_standard_description"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/tracking_protection_standard_option" />
|
|
||||||
|
|
||||||
<org.mozilla.fenix.onboarding.OnboardingRadioButton
|
<org.mozilla.fenix.onboarding.OnboardingRadioButton
|
||||||
android:id="@+id/tracking_protection_standard_option"
|
android:id="@+id/tracking_protection_standard_option"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="16dp"
|
||||||
android:paddingStart="0dp"
|
android:background="@android:color/transparent"
|
||||||
android:paddingEnd="8dp"
|
|
||||||
android:checked="true"
|
android:checked="true"
|
||||||
|
android:foreground="@drawable/rounded_ripple"
|
||||||
|
android:gravity="top"
|
||||||
|
android:paddingStart="8dp"
|
||||||
|
android:paddingEnd="8dp"
|
||||||
android:theme="@style/Checkable.Colored"
|
android:theme="@style/Checkable.Colored"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/description_text"
|
app:layout_constraintTop_toBottomOf="@id/description_text"
|
||||||
app:onboardingKey="@string/pref_key_tracking_protection_standard_option" />
|
app:onboardingKey="@string/pref_key_tracking_protection_standard_option"
|
||||||
|
app:onboardingKeyDescription="@string/onboarding_tracking_protection_standard_button_description_2"
|
||||||
<TextView
|
app:onboardingKeyTitle="@string/onboarding_tracking_protection_standard_button_2"
|
||||||
android:id="@+id/protection_standard_title"
|
tools:text="Standard" />
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/onboarding_tracking_protection_standard_button_2"
|
|
||||||
android:textColor="@color/primary_state_list_text_color"
|
|
||||||
android:textSize="16sp"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/tracking_protection_standard_option"
|
|
||||||
app:layout_constraintTop_toTopOf="@+id/tracking_protection_standard_option" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/protection_standard_description"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/onboarding_tracking_protection_standard_button_description_2"
|
|
||||||
android:textColor="@color/secondary_state_list_text_color"
|
|
||||||
android:textSize="14sp"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="@+id/protection_standard_title"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/protection_standard_title" />
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:id="@+id/clickable_region_strict"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:foreground="@drawable/rounded_ripple"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/protection_strict_description"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/tracking_protection_strict_default" />
|
|
||||||
|
|
||||||
<org.mozilla.fenix.onboarding.OnboardingRadioButton
|
<org.mozilla.fenix.onboarding.OnboardingRadioButton
|
||||||
android:id="@+id/tracking_protection_strict_default"
|
android:id="@+id/tracking_protection_strict_default"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="16dp"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
android:checked="false"
|
android:checked="false"
|
||||||
android:paddingStart="0dp"
|
android:foreground="@drawable/rounded_ripple"
|
||||||
|
android:gravity="top"
|
||||||
|
android:paddingStart="8dp"
|
||||||
android:paddingEnd="8dp"
|
android:paddingEnd="8dp"
|
||||||
|
android:textColor="@color/primary_state_list_text_color"
|
||||||
android:theme="@style/Checkable.Colored"
|
android:theme="@style/Checkable.Colored"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/tracking_protection_standard_option"
|
app:layout_constraintTop_toBottomOf="@id/tracking_protection_standard_option"
|
||||||
app:onboardingKey="@string/pref_key_tracking_protection_strict_default" />
|
app:onboardingKey="@string/pref_key_tracking_protection_strict_default"
|
||||||
|
app:onboardingKeyDescription="@string/onboarding_tracking_protection_strict_button_description_2"
|
||||||
<TextView
|
app:onboardingKeyTitle="@string/onboarding_tracking_protection_strict_option"
|
||||||
android:id="@+id/protection_strict_title"
|
tools:text="Strict" />
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/onboarding_tracking_protection_strict_option"
|
|
||||||
android:textColor="@color/primary_state_list_text_color"
|
|
||||||
android:textSize="16sp"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/tracking_protection_strict_default"
|
|
||||||
app:layout_constraintTop_toTopOf="@+id/tracking_protection_strict_default" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/protection_strict_description"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/onboarding_tracking_protection_strict_button_description_2"
|
|
||||||
android:textColor="@color/secondary_state_list_text_color"
|
|
||||||
android:textSize="14sp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="@+id/protection_strict_title"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/protection_strict_title" />
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
|
@ -9,12 +9,13 @@
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:layout_width="16dp"
|
android:layout_width="@dimen/cfr_triangle_width"
|
||||||
android:layout_height="16dp"
|
android:layout_height="@dimen/cfr_triangle_height"
|
||||||
android:layout_gravity="end"
|
android:layout_gravity="end"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="@dimen/cfr_triangle_margin_edge"
|
||||||
android:importantForAccessibility="no"
|
android:importantForAccessibility="no"
|
||||||
app:srcCompat="@drawable/ic_pbm_triangle" />
|
app:srcCompat="@drawable/ic_cfr_triangle"
|
||||||
|
app:tint="#7542E5" />
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -13,11 +13,12 @@
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
android:id="@+id/drop_down_triangle"
|
android:id="@+id/drop_down_triangle"
|
||||||
android:layout_width="@dimen/tp_onboarding_triangle_width"
|
android:layout_width="@dimen/cfr_triangle_width"
|
||||||
android:layout_height="@dimen/tp_onboarding_triangle_height"
|
android:layout_height="@dimen/cfr_triangle_height"
|
||||||
android:importantForAccessibility="no"
|
android:importantForAccessibility="no"
|
||||||
android:rotation="0"
|
android:rotation="0"
|
||||||
app:srcCompat="@drawable/ic_pbm_triangle"
|
app:srcCompat="@drawable/ic_cfr_triangle"
|
||||||
|
app:tint="#7542E5"
|
||||||
android:layout_gravity="center" />
|
android:layout_gravity="center" />
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
@ -92,9 +93,10 @@
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/pop_up_triangle"
|
android:id="@+id/pop_up_triangle"
|
||||||
android:layout_width="16dp"
|
android:layout_width="16dp"
|
||||||
android:layout_height="@dimen/tp_onboarding_triangle_height"
|
android:layout_height="@dimen/cfr_triangle_height"
|
||||||
android:importantForAccessibility="no"
|
android:importantForAccessibility="no"
|
||||||
android:rotation="180"
|
android:rotation="180"
|
||||||
app:srcCompat="@drawable/ic_pbm_triangle"
|
app:srcCompat="@drawable/ic_cfr_triangle"
|
||||||
|
app:tint="#7542E5"
|
||||||
android:layout_gravity="center" />
|
android:layout_gravity="center" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
|
@ -25,8 +25,8 @@
|
||||||
|
|
||||||
<androidx.cardview.widget.CardView
|
<androidx.cardview.widget.CardView
|
||||||
android:id="@+id/mozac_browser_tabstray_card"
|
android:id="@+id/mozac_browser_tabstray_card"
|
||||||
android:layout_width="92dp"
|
android:layout_width="@dimen/tab_tray_thumbnail_width"
|
||||||
android:layout_height="69dp"
|
android:layout_height="@dimen/tab_tray_thumbnail_height"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:backgroundTint="?tabTrayThumbnailItemBackground"
|
android:backgroundTint="?tabTrayThumbnailItemBackground"
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?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/. -->
|
||||||
|
<FrameLayout
|
||||||
|
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/counter_root"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:layout_centerVertical="true">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/counter_box"
|
||||||
|
android:layout_width="@dimen/tab_counter_box_width_height"
|
||||||
|
android:layout_height="@dimen/tab_counter_box_width_height"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
app:tint="@color/tab_icon"
|
||||||
|
app:srcCompat="@drawable/ic_tabs"/>
|
||||||
|
|
||||||
|
<!-- This text size auto adjusts based on num digits in `TabCounter` -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/counter_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textColor="@color/tab_icon"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:text="16" />
|
||||||
|
</FrameLayout>
|
|
@ -11,12 +11,13 @@
|
||||||
<ImageView
|
<ImageView
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
android:id="@+id/drop_down_triangle"
|
android:id="@+id/drop_down_triangle"
|
||||||
android:layout_width="@dimen/tp_onboarding_triangle_width"
|
android:layout_width="@dimen/cfr_triangle_width"
|
||||||
android:layout_height="@dimen/tp_onboarding_triangle_height"
|
android:layout_height="@dimen/cfr_triangle_height"
|
||||||
android:layout_marginStart="@dimen/tp_onboarding_triangle_margin_start"
|
android:layout_marginStart="@dimen/cfr_triangle_margin_edge"
|
||||||
android:importantForAccessibility="no"
|
android:importantForAccessibility="no"
|
||||||
android:rotation="0"
|
android:rotation="0"
|
||||||
app:srcCompat="@drawable/ic_triangle"
|
app:srcCompat="@drawable/ic_cfr_triangle"
|
||||||
|
app:tint="#0250BB"
|
||||||
android:layout_gravity="start" />
|
android:layout_gravity="start" />
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
@ -36,7 +37,7 @@
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:contentDescription="@string/onboarding_close"
|
android:contentDescription="@string/onboarding_close"
|
||||||
app:srcCompat="@drawable/ic_close"
|
app:srcCompat="@drawable/ic_close"
|
||||||
android:tint="@color/primary_text_dark_theme"
|
app:tint="@color/primary_text_dark_theme"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
@ -60,11 +61,12 @@
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/pop_up_triangle"
|
android:id="@+id/pop_up_triangle"
|
||||||
android:layout_width="16dp"
|
android:layout_width="@dimen/cfr_triangle_width"
|
||||||
android:layout_height="@dimen/tp_onboarding_triangle_height"
|
android:layout_height="@dimen/cfr_triangle_height"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="@dimen/cfr_triangle_margin_edge"
|
||||||
android:importantForAccessibility="no"
|
android:importantForAccessibility="no"
|
||||||
android:rotation="180"
|
android:rotation="180"
|
||||||
app:srcCompat="@drawable/ic_triangle"
|
app:srcCompat="@drawable/ic_cfr_triangle"
|
||||||
|
app:tint="#0250BB"
|
||||||
android:layout_gravity="start" />
|
android:layout_gravity="start" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
|
@ -78,7 +78,7 @@
|
||||||
<!-- Browser menu button that opens the addon manager -->
|
<!-- Browser menu button that opens the addon manager -->
|
||||||
<string name="browser_menu_add_ons">Askouezhioù</string>
|
<string name="browser_menu_add_ons">Askouezhioù</string>
|
||||||
<!-- Text displayed when there are no add-ons to be shown -->
|
<!-- Text displayed when there are no add-ons to be shown -->
|
||||||
<string name="no_add_ons">Nʼeus tamm enlugellad ebet amañ</string>
|
<string name="no_add_ons">Nʼeus tamm askouezh ebet amañ</string>
|
||||||
<!-- Browser menu button that sends a user to help articles -->
|
<!-- Browser menu button that sends a user to help articles -->
|
||||||
<string name="browser_menu_help">Skoazell</string>
|
<string name="browser_menu_help">Skoazell</string>
|
||||||
<!-- Browser menu button that sends a to a the what's new article -->
|
<!-- Browser menu button that sends a to a the what's new article -->
|
||||||
|
@ -296,7 +296,7 @@
|
||||||
<!-- Text shown when user enters empty device name -->
|
<!-- Text shown when user enters empty device name -->
|
||||||
<string name="empty_device_name_error">Anv an trevnad nʼhall ket bezañ goullo.</string>
|
<string name="empty_device_name_error">Anv an trevnad nʼhall ket bezañ goullo.</string>
|
||||||
<!-- Label indicating that sync is in progress -->
|
<!-- Label indicating that sync is in progress -->
|
||||||
<string name="sync_syncing_in_progress">O goubredañ...</string>
|
<string name="sync_syncing_in_progress">O c’houbredañ...</string>
|
||||||
<!-- Label summary indicating that sync failed. The first parameter is the date stamp showing last time it succeeded -->
|
<!-- Label summary indicating that sync failed. The first parameter is the date stamp showing last time it succeeded -->
|
||||||
<string name="sync_failed_summary">Goubredañ cʼhwitet. Berzh diwezhañ: %s</string>
|
<string name="sync_failed_summary">Goubredañ cʼhwitet. Berzh diwezhañ: %s</string>
|
||||||
|
|
||||||
|
@ -390,7 +390,7 @@
|
||||||
<!-- Preference for using top toolbar -->
|
<!-- Preference for using top toolbar -->
|
||||||
<string name="preference_top_toolbar">Krecʼh</string>
|
<string name="preference_top_toolbar">Krecʼh</string>
|
||||||
<!-- Preference for using bottom toolbar -->
|
<!-- Preference for using bottom toolbar -->
|
||||||
<string name="preference_bottom_toolbar">Diaz</string>
|
<string name="preference_bottom_toolbar">Traoñ</string>
|
||||||
|
|
||||||
<!-- Theme Preferences -->
|
<!-- Theme Preferences -->
|
||||||
<!-- Preference for using light theme -->
|
<!-- Preference for using light theme -->
|
||||||
|
@ -398,7 +398,7 @@
|
||||||
<!-- Preference for using dark theme -->
|
<!-- Preference for using dark theme -->
|
||||||
<string name="preference_dark_theme">Teñval</string>
|
<string name="preference_dark_theme">Teñval</string>
|
||||||
<!-- Preference for using using dark or light theme automatically set by battery -->
|
<!-- Preference for using using dark or light theme automatically set by battery -->
|
||||||
<string name="preference_auto_battery_theme">Lakaet gant an esperner tredan</string>
|
<string name="preference_auto_battery_theme">Dibabet gant an esperner tredan</string>
|
||||||
<!-- Preference for using following device theme -->
|
<!-- Preference for using following device theme -->
|
||||||
<string name="preference_follow_device_theme">Mont gant neuz ar benveg</string>
|
<string name="preference_follow_device_theme">Mont gant neuz ar benveg</string>
|
||||||
|
|
||||||
|
@ -474,7 +474,7 @@
|
||||||
<!-- Open tabs menu item to share all tabs -->
|
<!-- Open tabs menu item to share all tabs -->
|
||||||
<string name="tabs_menu_share_tabs">Rannañ an ivinelloù</string>
|
<string name="tabs_menu_share_tabs">Rannañ an ivinelloù</string>
|
||||||
<!-- Open tabs menu item to save tabs to collection -->
|
<!-- Open tabs menu item to save tabs to collection -->
|
||||||
<string name="tabs_menu_save_to_collection1">Enrollañ an ivinelloù en dastumad</string>
|
<string name="tabs_menu_save_to_collection1">Enrollañ an ivinelloù en un dastumad</string>
|
||||||
|
|
||||||
<!-- Content description (not visible, for screen readers etc.): Opens the tab menu when pressed -->
|
<!-- Content description (not visible, for screen readers etc.): Opens the tab menu when pressed -->
|
||||||
<string name="tab_menu">Lañser an ivinell</string>
|
<string name="tab_menu">Lañser an ivinell</string>
|
||||||
|
@ -690,7 +690,7 @@
|
||||||
<!-- Content description (not visible, for screen readers etc.): Opens the collection menu when pressed -->
|
<!-- Content description (not visible, for screen readers etc.): Opens the collection menu when pressed -->
|
||||||
<string name="collection_menu_button_content_description">Lañser an dastumadoù</string>
|
<string name="collection_menu_button_content_description">Lañser an dastumadoù</string>
|
||||||
<!-- No Open Tabs Message Header -->
|
<!-- No Open Tabs Message Header -->
|
||||||
<string name="no_collections_header1">Dastumit ar pezh a gont evidocʼh</string>
|
<string name="no_collections_header1">Dastumit ar pezh a zo pouezus evidoc‘h</string>
|
||||||
<!-- Label to describe what collections are to a new user without any collections -->
|
<!-- Label to describe what collections are to a new user without any collections -->
|
||||||
<string name="no_collections_description1">Strollit ar cʼhlaskoù, al lecʼhiennoù hag an ivinelloù heñvel evit mont daveto buanocʼh.</string>
|
<string name="no_collections_description1">Strollit ar cʼhlaskoù, al lecʼhiennoù hag an ivinelloù heñvel evit mont daveto buanocʼh.</string>
|
||||||
<!-- Title for the "select tabs" step of the collection creator -->
|
<!-- Title for the "select tabs" step of the collection creator -->
|
||||||
|
@ -863,7 +863,7 @@
|
||||||
<!-- Title for the cached images and files item in Delete browsing data -->
|
<!-- Title for the cached images and files item in Delete browsing data -->
|
||||||
<string name="preferences_delete_browsing_data_cached_files">Skeudennoù ha restroù er c’hrubuilh</string>
|
<string name="preferences_delete_browsing_data_cached_files">Skeudennoù ha restroù er c’hrubuilh</string>
|
||||||
<!-- Subtitle for the cached images and files item in Delete browsing data -->
|
<!-- Subtitle for the cached images and files item in Delete browsing data -->
|
||||||
<string name="preferences_delete_browsing_data_cached_files_subtitle">Dieubiñ a ra egor kadaviñ</string>
|
<string name="preferences_delete_browsing_data_cached_files_subtitle">Dieubiñ a raio egor kadaviñ</string>
|
||||||
|
|
||||||
<!-- Title for the site permissions item in Delete browsing data -->
|
<!-- Title for the site permissions item in Delete browsing data -->
|
||||||
<string name="preferences_delete_browsing_data_site_permissions">Aotreoù al lec’hienn</string>
|
<string name="preferences_delete_browsing_data_site_permissions">Aotreoù al lec’hienn</string>
|
||||||
|
@ -1170,7 +1170,7 @@
|
||||||
<string name="browser_toolbar_url_copied_to_clipboard_snackbar">URL eilet er golver</string>
|
<string name="browser_toolbar_url_copied_to_clipboard_snackbar">URL eilet er golver</string>
|
||||||
|
|
||||||
<!-- Title text for the Add To Homescreen dialog -->
|
<!-- Title text for the Add To Homescreen dialog -->
|
||||||
<string name="add_to_homescreen_title">Ouzhpennañ dʼar skramm degemer</string>
|
<string name="add_to_homescreen_title">Lakaat er skramm degemer</string>
|
||||||
<!-- Cancel button text for the Add to Homescreen dialog -->
|
<!-- Cancel button text for the Add to Homescreen dialog -->
|
||||||
<string name="add_to_homescreen_cancel">Nullañ</string>
|
<string name="add_to_homescreen_cancel">Nullañ</string>
|
||||||
<!-- Add button text for the Add to Homescreen dialog -->
|
<!-- Add button text for the Add to Homescreen dialog -->
|
||||||
|
@ -1365,7 +1365,7 @@
|
||||||
<!-- Bookmark deletion confirmation -->
|
<!-- Bookmark deletion confirmation -->
|
||||||
<string name="bookmark_deletion_confirmation">Ha fellout a ra deocʼh dilemel ar sined-mañ ?</string>
|
<string name="bookmark_deletion_confirmation">Ha fellout a ra deocʼh dilemel ar sined-mañ ?</string>
|
||||||
<!-- Browser menu button that adds a top site to the home fragment -->
|
<!-- Browser menu button that adds a top site to the home fragment -->
|
||||||
<string name="browser_menu_add_to_top_sites">Ouzhpennañ dʼal lecʼhiennoù gwellañ</string>
|
<string name="browser_menu_add_to_top_sites">Lakaat el lecʼhiennoù gwellañ</string>
|
||||||
<!-- text shown before the issuer name to indicate who its verified by, parameter is the name of
|
<!-- text shown before the issuer name to indicate who its verified by, parameter is the name of
|
||||||
the certificate authority that verified the ticket-->
|
the certificate authority that verified the ticket-->
|
||||||
<string name="certificate_info_verified_by">Gwiriet gant:%1$s</string>
|
<string name="certificate_info_verified_by">Gwiriet gant:%1$s</string>
|
||||||
|
|
|
@ -919,6 +919,20 @@
|
||||||
<!-- text for firefox preview moving tip header. "Firefox Nightly" is intentionally hardcoded -->
|
<!-- text for firefox preview moving tip header. "Firefox Nightly" is intentionally hardcoded -->
|
||||||
<string name="tip_firefox_preview_moved_header_preview_installed">Firefox Nightly हलले आहे</string>
|
<string name="tip_firefox_preview_moved_header_preview_installed">Firefox Nightly हलले आहे</string>
|
||||||
|
|
||||||
|
<!-- text for firefox preview moving tip description -->
|
||||||
|
<string name="tip_firefox_preview_moved_description_preview_installed">या अॅपला यापुढे सुरक्षा अद्यतने प्राप्त होणार नाहीत. हे अॅप वापरणे थांबवा आणि नवीन Nightly वर स्विच करा.
|
||||||
|
\n\nआपल्या वाचनखुणा, लॉगिन, आणि इतिहास इतर अॅप वर स्थानांतरित करण्यासाठी, एक Firefox खाते त.ार करा.</string>
|
||||||
|
<!-- text for firefox preview moving tip button -->
|
||||||
|
<string name="tip_firefox_preview_moved_button_preview_installed">नवीन Nightly वर स्विच करा</string>
|
||||||
|
|
||||||
|
<!-- text for firefox preview moving tip header. "Firefox Nightly" is intentionally hardcoded -->
|
||||||
|
<string name="tip_firefox_preview_moved_header_preview_not_installed">Firefox Nightly हलले आहे</string>
|
||||||
|
<!-- text for firefox preview moving tip description -->
|
||||||
|
<string name="tip_firefox_preview_moved_description_preview_not_installed">या अॅपला यापुढे सुरक्षा अद्यतने प्राप्त होणार नाहीत. नवीन Nightly मिळवा आणि हे अॅप वापरणे थांबवा.
|
||||||
|
\n\nआपल्या वाचनखुणा, लॉगिन, आणि इतिहास इतर अॅप वर स्थानांतरित करण्यासाठी, एक Firefox खाते त.ार करा.</string>
|
||||||
|
<!-- text for firefox preview moving tip button -->
|
||||||
|
<string name="tip_firefox_preview_moved_button_preview_not_installed">नवीन Nightly मिळवा</string>
|
||||||
|
|
||||||
<!-- Onboarding -->
|
<!-- Onboarding -->
|
||||||
<!-- Text for onboarding welcome message
|
<!-- Text for onboarding welcome message
|
||||||
The first parameter is the name of the app (e.g. Firefox Preview) -->
|
The first parameter is the name of the app (e.g. Firefox Preview) -->
|
||||||
|
@ -954,6 +968,8 @@
|
||||||
<string name="onboarding_firefox_account_sync_is_on">सिंक चालू आहे</string>
|
<string name="onboarding_firefox_account_sync_is_on">सिंक चालू आहे</string>
|
||||||
<!-- text to display in the snackbar if automatic sign-in fails. user may try again -->
|
<!-- text to display in the snackbar if automatic sign-in fails. user may try again -->
|
||||||
<string name="onboarding_firefox_account_automatic_signin_failed">साइन इन करण्यात अयशस्वी</string>
|
<string name="onboarding_firefox_account_automatic_signin_failed">साइन इन करण्यात अयशस्वी</string>
|
||||||
|
<!-- text for the tracking protection onboarding card header -->
|
||||||
|
<string name="onboarding_tracking_protection_header_2">स्वयंचलित गोपनीयता</string>
|
||||||
<!-- text for tracking protection radio button option for strict level of blocking -->
|
<!-- text for tracking protection radio button option for strict level of blocking -->
|
||||||
<string name="onboarding_tracking_protection_strict_button">कठोर (सुचवलेले)</string>
|
<string name="onboarding_tracking_protection_strict_button">कठोर (सुचवलेले)</string>
|
||||||
<!-- text for the toolbar position card header
|
<!-- text for the toolbar position card header
|
||||||
|
|
|
@ -16,6 +16,13 @@
|
||||||
<!-- No Open Tabs Message Description -->
|
<!-- No Open Tabs Message Description -->
|
||||||
<string name="no_open_tabs_description">Filele deschise vor fi afișate aici.</string>
|
<string name="no_open_tabs_description">Filele deschise vor fi afișate aici.</string>
|
||||||
|
|
||||||
|
<!-- No Private Tabs Message Description -->
|
||||||
|
<string name="no_private_tabs_description">Aici vor fi afișate filele tale private.</string>
|
||||||
|
<!-- Message announced to the user when tab tray is selected with 1 tab -->
|
||||||
|
<string name="open_tab_tray_single">1 filă deschisă. Atinge pentru a comuta filele.</string>
|
||||||
|
<!-- Message announced to the user when tab tray is selected with 0 or 2+ tabs -->
|
||||||
|
<string name="open_tab_tray_plural">%1$s file deschise. Atinge pentru a comuta filele.</string>
|
||||||
|
|
||||||
<!-- About content. The first parameter is the name of the application. (For example: Fenix) -->
|
<!-- About content. The first parameter is the name of the application. (For example: Fenix) -->
|
||||||
<string name="about_content">%1$s este realizat de Mozilla.</string>
|
<string name="about_content">%1$s este realizat de Mozilla.</string>
|
||||||
|
|
||||||
|
@ -38,6 +45,9 @@
|
||||||
<!-- Text for the negative button -->
|
<!-- Text for the negative button -->
|
||||||
<string name="cfr_neg_button_text">Nu, mulțumesc</string>
|
<string name="cfr_neg_button_text">Nu, mulțumesc</string>
|
||||||
|
|
||||||
|
<!-- Search widget "contextual feature recommendation" (CFR) -->
|
||||||
|
<!-- Text for the main message. 'Firefox' intentionally hardcoded here.-->
|
||||||
|
<string name="search_widget_cfr_message">Accesează Firefox mai repede. Adaugă un widget pe ecranul de start.</string>
|
||||||
<!-- Text for the positive button -->
|
<!-- Text for the positive button -->
|
||||||
<string name="search_widget_cfr_pos_button_text">Adaugă widget</string>
|
<string name="search_widget_cfr_pos_button_text">Adaugă widget</string>
|
||||||
<!-- Text for the negative button -->
|
<!-- Text for the negative button -->
|
||||||
|
@ -110,6 +120,8 @@
|
||||||
<string name="browser_menu_powered_by2">Cu tehnologie %1$s</string>
|
<string name="browser_menu_powered_by2">Cu tehnologie %1$s</string>
|
||||||
<!-- Browser menu button to put the current page in reader mode -->
|
<!-- Browser menu button to put the current page in reader mode -->
|
||||||
<string name="browser_menu_read">Mod de lectură</string>
|
<string name="browser_menu_read">Mod de lectură</string>
|
||||||
|
<!-- Browser menu button content description to close reader mode and return the user to the regular browser -->
|
||||||
|
<string name="browser_menu_read_close">Închide modul de lectură</string>
|
||||||
<!-- Browser menu button to open the current page in an external app -->
|
<!-- Browser menu button to open the current page in an external app -->
|
||||||
<string name="browser_menu_open_app_link">Deschide în aplicație</string>
|
<string name="browser_menu_open_app_link">Deschide în aplicație</string>
|
||||||
<!-- Browser menu button to configure reader mode appearance e.g. the used font type and size -->
|
<!-- Browser menu button to configure reader mode appearance e.g. the used font type and size -->
|
||||||
|
@ -251,6 +263,8 @@
|
||||||
<string name="preferences_show_search_shortcuts">Afișează comenzile rapide pentru căutări</string>
|
<string name="preferences_show_search_shortcuts">Afișează comenzile rapide pentru căutări</string>
|
||||||
<!-- Preference title for switch preference to show search suggestions -->
|
<!-- Preference title for switch preference to show search suggestions -->
|
||||||
<string name="preferences_show_search_suggestions">Afișează sugestii de căutare</string>
|
<string name="preferences_show_search_suggestions">Afișează sugestii de căutare</string>
|
||||||
|
<!-- Preference title for switch preference to show voice search button -->
|
||||||
|
<string name="preferences_show_voice_search">Afișează căutarea vocală</string>
|
||||||
<!-- Preference title for switch preference to show search suggestions also in private mode -->
|
<!-- Preference title for switch preference to show search suggestions also in private mode -->
|
||||||
<string name="preferences_show_search_suggestions_in_private">Afișează în sesiuni private</string>
|
<string name="preferences_show_search_suggestions_in_private">Afișează în sesiuni private</string>
|
||||||
<!-- Preference title for switch preference to show a clipboard suggestion when searching -->
|
<!-- Preference title for switch preference to show a clipboard suggestion when searching -->
|
||||||
|
@ -367,6 +381,9 @@
|
||||||
<!-- Preference for removing FxA account -->
|
<!-- Preference for removing FxA account -->
|
||||||
<string name="preferences_sync_remove_account">Șterge contul</string>
|
<string name="preferences_sync_remove_account">Șterge contul</string>
|
||||||
|
|
||||||
|
<!-- Pairing Feature strings -->
|
||||||
|
<!-- Instructions on how to access pairing -->
|
||||||
|
<string name="pair_instructions_2"><![CDATA[Scanează codul QR afișat pe <b>firefox.com/pair</b>]]></string>
|
||||||
<!-- Button to open camera for pairing -->
|
<!-- Button to open camera for pairing -->
|
||||||
<string name="pair_open_camera">Cameră deschisă</string>
|
<string name="pair_open_camera">Cameră deschisă</string>
|
||||||
<!-- Button to cancel pairing -->
|
<!-- Button to cancel pairing -->
|
||||||
|
@ -408,6 +425,8 @@
|
||||||
<!-- Option in Library to open History page -->
|
<!-- Option in Library to open History page -->
|
||||||
<string name="library_history">Istoric</string>
|
<string name="library_history">Istoric</string>
|
||||||
|
|
||||||
|
<!-- Option in Library to open Synced Tabs page -->
|
||||||
|
<string name="library_synced_tabs">File sincronizate</string>
|
||||||
<!-- Option in Library to open Reading List -->
|
<!-- Option in Library to open Reading List -->
|
||||||
<string name="library_reading_list">Listă de lectură</string>
|
<string name="library_reading_list">Listă de lectură</string>
|
||||||
<!-- Menu Item Label for Search in Library -->
|
<!-- Menu Item Label for Search in Library -->
|
||||||
|
@ -430,6 +449,24 @@
|
||||||
<string name="add_tab">Adaugă fila</string>
|
<string name="add_tab">Adaugă fila</string>
|
||||||
<!-- Content description (not visible, for screen readers etc.): Add tab button. Adds a news tab when pressed -->
|
<!-- Content description (not visible, for screen readers etc.): Add tab button. Adds a news tab when pressed -->
|
||||||
<string name="add_private_tab">Adaugă filă privată</string>
|
<string name="add_private_tab">Adaugă filă privată</string>
|
||||||
|
<!-- Text for the new tab button to indicate adding a new private tab in the tab -->
|
||||||
|
<string name="tab_drawer_fab_content">Privată</string>
|
||||||
|
<!-- Text shown as the title of the open tab tray -->
|
||||||
|
<string name="tab_tray_title">File deschise</string>
|
||||||
|
<!-- Text shown in the menu for saving tabs to a collection -->
|
||||||
|
<string name="tab_tray_menu_item_save">Salvează în colecție</string>
|
||||||
|
<!-- Text shown in the menu for sharing all tabs -->
|
||||||
|
<string name="tab_tray_menu_item_share">Partajează toate filele</string>
|
||||||
|
<!-- Text shown in the menu for closing all tabs -->
|
||||||
|
<string name="tab_tray_menu_item_close">Închide toate filele</string>
|
||||||
|
<!-- Shortcut action to open new tab -->
|
||||||
|
<string name="tab_tray_menu_open_new_tab">Filă nouă</string>
|
||||||
|
<!-- Shortcut action to open the home screen -->
|
||||||
|
<string name="tab_tray_menu_home">Acasă</string>
|
||||||
|
<!-- Shortcut action to toggle private mode -->
|
||||||
|
<string name="tab_tray_menu_toggle">Mod de comutare a filelor</string>
|
||||||
|
<!-- Content description (not visible, for screen readers etc.): Removes tab from collection button. Removes the selected tab from collection when pressed -->
|
||||||
|
<string name="remove_tab_from_collection">Elimină fila din colecție</string>
|
||||||
<!-- Content description (not visible, for screen readers etc.): Close tab button. Closes the current session when pressed -->
|
<!-- Content description (not visible, for screen readers etc.): Close tab button. Closes the current session when pressed -->
|
||||||
<string name="close_tab">Închide fila</string>
|
<string name="close_tab">Închide fila</string>
|
||||||
<!-- Content description (not visible, for screen readers etc.): Close tab <title> button. First parameter is tab title -->
|
<!-- Content description (not visible, for screen readers etc.): Close tab <title> button. First parameter is tab title -->
|
||||||
|
@ -440,6 +477,8 @@
|
||||||
<string name="tabs_menu_close_all_tabs">Închide toate filele</string>
|
<string name="tabs_menu_close_all_tabs">Închide toate filele</string>
|
||||||
<!-- Open tabs menu item to share all tabs -->
|
<!-- Open tabs menu item to share all tabs -->
|
||||||
<string name="tabs_menu_share_tabs">Partajează filele</string>
|
<string name="tabs_menu_share_tabs">Partajează filele</string>
|
||||||
|
<!-- Open tabs menu item to save tabs to collection -->
|
||||||
|
<string name="tabs_menu_save_to_collection1">Salvează filele în colecție</string>
|
||||||
<!-- Content description (not visible, for screen readers etc.): Opens the tab menu when pressed -->
|
<!-- Content description (not visible, for screen readers etc.): Opens the tab menu when pressed -->
|
||||||
<string name="tab_menu">Meniu de file</string>
|
<string name="tab_menu">Meniu de file</string>
|
||||||
<!-- Tab menu item to share the tab -->
|
<!-- Tab menu item to share the tab -->
|
||||||
|
@ -463,6 +502,9 @@
|
||||||
<!-- Text for the menu button to remove a top site -->
|
<!-- Text for the menu button to remove a top site -->
|
||||||
<string name="remove_top_site">Șterge</string>
|
<string name="remove_top_site">Șterge</string>
|
||||||
|
|
||||||
|
<!-- Postfix for private WebApp titles, placeholder is replaced with app name -->
|
||||||
|
<string name="pwa_site_controls_title_private">%1$s (mod privat)</string>
|
||||||
|
|
||||||
<!-- History -->
|
<!-- History -->
|
||||||
<!-- Text for the button to clear all history -->
|
<!-- Text for the button to clear all history -->
|
||||||
<string name="history_delete_all">Șterge istoricul</string>
|
<string name="history_delete_all">Șterge istoricul</string>
|
||||||
|
@ -652,6 +694,10 @@
|
||||||
<!-- Content description (not visible, for screen readers etc.): Opens the collection menu when pressed -->
|
<!-- Content description (not visible, for screen readers etc.): Opens the collection menu when pressed -->
|
||||||
<string name="collection_menu_button_content_description">Meniu de colecții</string>
|
<string name="collection_menu_button_content_description">Meniu de colecții</string>
|
||||||
|
|
||||||
|
<!-- No Open Tabs Message Header -->
|
||||||
|
<string name="no_collections_header1">Colectează ce te interesează</string>
|
||||||
|
<!-- Label to describe what collections are to a new user without any collections -->
|
||||||
|
<string name="no_collections_description1">Grupează căutările similare, site-urile și filele pentru acces mai rapid ulterior.</string>
|
||||||
<!-- Title for the "select tabs" step of the collection creator -->
|
<!-- Title for the "select tabs" step of the collection creator -->
|
||||||
<string name="create_collection_select_tabs">Selectează filele</string>
|
<string name="create_collection_select_tabs">Selectează filele</string>
|
||||||
<!-- Title for the "select collection" step of the collection creator -->
|
<!-- Title for the "select collection" step of the collection creator -->
|
||||||
|
@ -681,6 +727,9 @@
|
||||||
<!-- Button to save currently selected tabs in the "select tabs" step of the collection creator-->
|
<!-- Button to save currently selected tabs in the "select tabs" step of the collection creator-->
|
||||||
<string name="create_collection_save">Salvează</string>
|
<string name="create_collection_save">Salvează</string>
|
||||||
|
|
||||||
|
<!-- Snackbar action to view the collection the user just created or updated -->
|
||||||
|
<string name="create_collection_view">Afișează</string>
|
||||||
|
|
||||||
<!-- Default name for a new collection in "name new collection" step of the collection creator. %d is a placeholder for the number of collections-->
|
<!-- Default name for a new collection in "name new collection" step of the collection creator. %d is a placeholder for the number of collections-->
|
||||||
<string name="create_collection_default_name">Colecția %d</string>
|
<string name="create_collection_default_name">Colecția %d</string>
|
||||||
|
|
||||||
|
@ -791,11 +840,15 @@
|
||||||
<!-- Title for Accessibility Text Size Scaling Preference -->
|
<!-- Title for Accessibility Text Size Scaling Preference -->
|
||||||
<string name="preference_accessibility_font_size_title">Dimensiunea fontului</string>
|
<string name="preference_accessibility_font_size_title">Dimensiunea fontului</string>
|
||||||
|
|
||||||
|
<!-- Title for Accessibility Text Automatic Size Scaling Preference -->
|
||||||
|
<string name="preference_accessibility_auto_size_2">Mărime automată a fontului</string>
|
||||||
<!-- Summary for Accessibility Text Automatic Size Scaling Preference -->
|
<!-- Summary for Accessibility Text Automatic Size Scaling Preference -->
|
||||||
<string name="preference_accessibility_auto_size_summary">Dimensiunea fontului va coincide cu cea din setările Android. Dezactivează pentru a gestiona aici dimensiunea fontului.</string>
|
<string name="preference_accessibility_auto_size_summary">Dimensiunea fontului va coincide cu cea din setările Android. Dezactivează pentru a gestiona aici dimensiunea fontului.</string>
|
||||||
|
|
||||||
<!-- Title for the Delete browsing data preference -->
|
<!-- Title for the Delete browsing data preference -->
|
||||||
<string name="preferences_delete_browsing_data">Șterge datele de navigare</string>
|
<string name="preferences_delete_browsing_data">Șterge datele de navigare</string>
|
||||||
|
<!-- Title for the tabs item in Delete browsing data -->
|
||||||
|
<string name="preferences_delete_browsing_data_tabs_title_2">File deschise</string>
|
||||||
<!-- Subtitle for the tabs item in Delete browsing data, parameter will be replaced with the number of open tabs -->
|
<!-- Subtitle for the tabs item in Delete browsing data, parameter will be replaced with the number of open tabs -->
|
||||||
<string name="preferences_delete_browsing_data_tabs_subtitle">%d (de) file</string>
|
<string name="preferences_delete_browsing_data_tabs_subtitle">%d (de) file</string>
|
||||||
|
|
||||||
|
@ -827,8 +880,6 @@
|
||||||
<string name="preference_summary_delete_browsing_data_on_quit">Șterge automat datele de navigare când selectezi „Închide” în meniul principal</string>
|
<string name="preference_summary_delete_browsing_data_on_quit">Șterge automat datele de navigare când selectezi „Închide” în meniul principal</string>
|
||||||
<!-- Summary for the Delete browsing data on quit preference. "Quit" translation should match delete_browsing_data_on_quit_action translation. -->
|
<!-- Summary for the Delete browsing data on quit preference. "Quit" translation should match delete_browsing_data_on_quit_action translation. -->
|
||||||
<string name="preference_summary_delete_browsing_data_on_quit_2">Șterge automat datele de navigare când selectezi \„Închide\” în meniul principal</string>
|
<string name="preference_summary_delete_browsing_data_on_quit_2">Șterge automat datele de navigare când selectezi \„Închide\” în meniul principal</string>
|
||||||
<!-- Category for history items to delete on quit in delete browsing data on quit -->
|
|
||||||
<string name="preferences_delete_browsing_data_on_quit_browsing_history">Istoric de navigare</string>
|
|
||||||
<!-- Action item in menu for the Delete browsing data on quit feature -->
|
<!-- Action item in menu for the Delete browsing data on quit feature -->
|
||||||
<string name="delete_browsing_data_on_quit_action">Închide</string>
|
<string name="delete_browsing_data_on_quit_action">Închide</string>
|
||||||
|
|
||||||
|
@ -852,6 +903,9 @@
|
||||||
<string name="tip_firefox_preview_moved_description">Firefox Nightly se actualizează în fiecare seară și are funcționalități experimentale noi
|
<string name="tip_firefox_preview_moved_description">Firefox Nightly se actualizează în fiecare seară și are funcționalități experimentale noi
|
||||||
Dar poate fi mai puțin stabil. Descarcă browserul nostru beta pentru o experiență mai stabilă.</string>
|
Dar poate fi mai puțin stabil. Descarcă browserul nostru beta pentru o experiență mai stabilă.</string>
|
||||||
|
|
||||||
|
<!-- text for firefox preview moving tip button. "Firefox for Android Beta" is intentionally hardcoded -->
|
||||||
|
<string name="tip_firefox_preview_moved_button_2">Descarcă Firefox Beta pentru Android</string>
|
||||||
|
|
||||||
<!-- text for firefox preview moving tip header. "Firefox Nightly" is intentionally hardcoded -->
|
<!-- text for firefox preview moving tip header. "Firefox Nightly" is intentionally hardcoded -->
|
||||||
<string name="tip_firefox_preview_moved_header_preview_installed">Firefox Nightly s-a mutat</string>
|
<string name="tip_firefox_preview_moved_header_preview_installed">Firefox Nightly s-a mutat</string>
|
||||||
<!-- text for firefox preview moving tip description -->
|
<!-- text for firefox preview moving tip description -->
|
||||||
|
@ -903,8 +957,21 @@
|
||||||
<string name="onboarding_firefox_account_sync_is_on">Sync este activat</string>
|
<string name="onboarding_firefox_account_sync_is_on">Sync este activat</string>
|
||||||
<!-- text to display in the snackbar if automatic sign-in fails. user may try again -->
|
<!-- text to display in the snackbar if automatic sign-in fails. user may try again -->
|
||||||
<string name="onboarding_firefox_account_automatic_signin_failed">Eroare de autentificare</string>
|
<string name="onboarding_firefox_account_automatic_signin_failed">Eroare de autentificare</string>
|
||||||
|
<!-- text for the tracking protection onboarding card header -->
|
||||||
|
<string name="onboarding_tracking_protection_header_2">Confidențialitate automată</string>
|
||||||
|
<!-- text for the tracking protection card description
|
||||||
|
The first parameter is the name of the app (e.g. Firefox Preview) -->
|
||||||
|
<string name="onboarding_tracking_protection_description_2">Setările de confidențialitate și securitate blochează elementele de urmărire, softurile rău-intenționate și firmele care te urmăresc.</string>
|
||||||
|
<!-- text for tracking protection radio button option for standard level of blocking -->
|
||||||
|
<string name="onboarding_tracking_protection_standard_button_2">Standard (implicit)</string>
|
||||||
|
<!-- text for standard blocking option button description -->
|
||||||
|
<string name="onboarding_tracking_protection_standard_button_description_2">Blochează mai puține elemente de urmărire. Paginile se vor încărca normal.</string>
|
||||||
<!-- text for tracking protection radio button option for strict level of blocking -->
|
<!-- text for tracking protection radio button option for strict level of blocking -->
|
||||||
<string name="onboarding_tracking_protection_strict_button">Strictă (recomandat)</string>
|
<string name="onboarding_tracking_protection_strict_button">Strictă (recomandat)</string>
|
||||||
|
<!-- text for tracking protection radio button option for strict level of blocking -->
|
||||||
|
<string name="onboarding_tracking_protection_strict_option">Strictă</string>
|
||||||
|
<!-- text for strict blocking option button description -->
|
||||||
|
<string name="onboarding_tracking_protection_strict_button_description_2">Blochează mai multe elemente de urmărire, reclame și ferestre pop-up. Paginile se încarcă mai repede, dar se poate ca unele funcționalități să nu meargă.</string>
|
||||||
<!-- text for the toolbar position card header
|
<!-- text for the toolbar position card header
|
||||||
In English this is an idiom for "choose a side as in an argument or fight"
|
In English this is an idiom for "choose a side as in an argument or fight"
|
||||||
but it is ok to make this more literally about "choosing a position in a physical space -->
|
but it is ok to make this more literally about "choosing a position in a physical space -->
|
||||||
|
@ -991,14 +1058,22 @@
|
||||||
<string name="preference_enhanced_tracking_protection_explanation">Păstrează-ți datele pentru tine. %s te protejează de multe dintre cele mai frecvente elemente de urmărire care monitorizează ce faci online.</string>
|
<string name="preference_enhanced_tracking_protection_explanation">Păstrează-ți datele pentru tine. %s te protejează de multe dintre cele mai frecvente elemente de urmărire care monitorizează ce faci online.</string>
|
||||||
<!-- Text displayed that links to website about enhanced tracking protection -->
|
<!-- Text displayed that links to website about enhanced tracking protection -->
|
||||||
<string name="preference_enhanced_tracking_protection_explanation_learn_more">Află mai multe</string>
|
<string name="preference_enhanced_tracking_protection_explanation_learn_more">Află mai multe</string>
|
||||||
|
<!-- Preference for enhanced tracking protection for the standard protection settings -->
|
||||||
|
<string name="preference_enhanced_tracking_protection_standard_default_1">Standard (implicit)</string>
|
||||||
|
<!-- Preference description for enhanced tracking protection for the standard protection settings -->
|
||||||
|
<string name="preference_enhanced_tracking_protection_standard_description_3">Blochează mai puține elemente de urmărire. Paginile se vor încărca normal.</string>
|
||||||
<!-- Accessibility text for the Standard protection information icon -->
|
<!-- Accessibility text for the Standard protection information icon -->
|
||||||
<string name="preference_enhanced_tracking_protection_standard_info_button">Ce blochează protecția standard împotriva urmăririi</string>
|
<string name="preference_enhanced_tracking_protection_standard_info_button">Ce blochează protecția standard împotriva urmăririi</string>
|
||||||
<!-- Preference for enhanced tracking protection for the strict protection settings -->
|
<!-- Preference for enhanced tracking protection for the strict protection settings -->
|
||||||
<string name="preference_enhanced_tracking_protection_strict">Strictă</string>
|
<string name="preference_enhanced_tracking_protection_strict">Strictă</string>
|
||||||
|
<!-- Preference description for enhanced tracking protection for the strict protection settings -->
|
||||||
|
<string name="preference_enhanced_tracking_protection_strict_description_2">Blochează mai multe elemente de urmărire, reclame și ferestre pop-up. Paginile se încarcă mai repede, dar se poate ca unele funcționalități să nu meargă.</string>
|
||||||
<!-- Accessibility text for the Strict protection information icon -->
|
<!-- Accessibility text for the Strict protection information icon -->
|
||||||
<string name="preference_enhanced_tracking_protection_strict_info_button">Ce blochează protecția strictă împotriva urmăririi</string>
|
<string name="preference_enhanced_tracking_protection_strict_info_button">Ce blochează protecția strictă împotriva urmăririi</string>
|
||||||
<!-- Preference for enhanced tracking protection for the custom protection settings -->
|
<!-- Preference for enhanced tracking protection for the custom protection settings -->
|
||||||
<string name="preference_enhanced_tracking_protection_custom">Personalizat</string>
|
<string name="preference_enhanced_tracking_protection_custom">Personalizat</string>
|
||||||
|
<!-- Preference description for enhanced tracking protection for the strict protection settings -->
|
||||||
|
<string name="preference_enhanced_tracking_protection_custom_description_2">Alege ce elemente de urmărire și scripturi să blochezi.</string>
|
||||||
<!-- Accessibility text for the Strict protection information icon -->
|
<!-- Accessibility text for the Strict protection information icon -->
|
||||||
<string name="preference_enhanced_tracking_protection_custom_info_button">Ce blochează protecția personalizată împotriva urmăririi</string>
|
<string name="preference_enhanced_tracking_protection_custom_info_button">Ce blochează protecția personalizată împotriva urmăririi</string>
|
||||||
<!-- Header for categories that are being blocked by current Enhanced Tracking Protection settings -->
|
<!-- Header for categories that are being blocked by current Enhanced Tracking Protection settings -->
|
||||||
|
@ -1048,6 +1123,8 @@
|
||||||
|
|
||||||
<!-- Description of tracking content that can be blocked by Enhanced Tracking Protection -->
|
<!-- Description of tracking content that can be blocked by Enhanced Tracking Protection -->
|
||||||
<string name="etp_tracking_content_description">Oprește încărcarea reclamelor, videoclipurilor și a altor conținuturi externe care conțin coduri de urmărire. Poate afecta anumite funcționalități ale site-ului.</string>
|
<string name="etp_tracking_content_description">Oprește încărcarea reclamelor, videoclipurilor și a altor conținuturi externe care conțin coduri de urmărire. Poate afecta anumite funcționalități ale site-ului.</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">Când scutul este violet, %s a blocat elemente de urmărire de pe un site. Atinge pentru mai multe informații.</string>
|
||||||
<!-- Enhanced Tracking Protection message that protection is currently on for this site -->
|
<!-- Enhanced Tracking Protection message that protection is currently on for this site -->
|
||||||
<string name="etp_panel_on">Protecțiile sunt ACTIVE pentru acest site</string>
|
<string name="etp_panel_on">Protecțiile sunt ACTIVE pentru acest site</string>
|
||||||
<!-- Enhanced Tracking Protection message that protection is currently off for this site -->
|
<!-- Enhanced Tracking Protection message that protection is currently off for this site -->
|
||||||
|
@ -1069,6 +1146,8 @@
|
||||||
|
|
||||||
<!-- About page link text to open support link -->
|
<!-- About page link text to open support link -->
|
||||||
<string name="about_support">Asistență</string>
|
<string name="about_support">Asistență</string>
|
||||||
|
<!-- About page link text to list of past crashes (like about:crashes on desktop) -->
|
||||||
|
<string name="about_crashes">Defecțiuni</string>
|
||||||
<!-- About page link text to open privacy notice link -->
|
<!-- About page link text to open privacy notice link -->
|
||||||
<string name="about_privacy_notice">Politică de confidențialitate</string>
|
<string name="about_privacy_notice">Politică de confidențialitate</string>
|
||||||
<!-- About page link text to open know your rights link -->
|
<!-- About page link text to open know your rights link -->
|
||||||
|
@ -1204,6 +1283,13 @@
|
||||||
<!-- Summary for Accessibility Force Enable Zoom Preference -->
|
<!-- Summary for Accessibility Force Enable Zoom Preference -->
|
||||||
<string name="preference_accessibility_force_enable_zoom_summary">Activează permiterea apropierii/depărtării cu degetele pentru zoom, chiar și pe site-uri web care împiedică acest gest.</string>
|
<string name="preference_accessibility_force_enable_zoom_summary">Activează permiterea apropierii/depărtării cu degetele pentru zoom, chiar și pe site-uri web care împiedică acest gest.</string>
|
||||||
|
|
||||||
|
<!-- Saved logins sorting strategy menu item -by name- (if selected, it will sort saved logins alphabetically) -->
|
||||||
|
<string name="saved_logins_sort_strategy_alphabetically">Denumire (A-Z)</string>
|
||||||
|
<!-- Saved logins sorting strategy menu item -by last used- (if selected, it will sort saved logins by last used) -->
|
||||||
|
<string name="saved_logins_sort_strategy_last_used">Folosite ultima dată</string>
|
||||||
|
<!-- Content description (not visible, for screen readers etc.): Sort saved logins dropdown menu chevron icon -->
|
||||||
|
<string name="saved_logins_menu_dropdown_chevron_icon_content_description">Meniu de sortare a datelor de autentificare</string>
|
||||||
|
|
||||||
<!-- Title of the Add search engine screen -->
|
<!-- Title of the Add search engine screen -->
|
||||||
<string name="search_engine_add_custom_search_engine_title">Adaugă un motor de căutare</string>
|
<string name="search_engine_add_custom_search_engine_title">Adaugă un motor de căutare</string>
|
||||||
<!-- Title of the Edit search engine screen -->
|
<!-- Title of the Edit search engine screen -->
|
||||||
|
@ -1296,11 +1382,57 @@
|
||||||
<string name="certificate_info_verified_by">Verificat de: %1$s</string>
|
<string name="certificate_info_verified_by">Verificat de: %1$s</string>
|
||||||
<!-- Login overflow menu delete button -->
|
<!-- Login overflow menu delete button -->
|
||||||
<string name="login_menu_delete_button">Șterge</string>
|
<string name="login_menu_delete_button">Șterge</string>
|
||||||
|
<!-- Login overflow menu edit button -->
|
||||||
|
<string name="login_menu_edit_button">Editează</string>
|
||||||
<!-- Message in delete confirmation dialog for logins -->
|
<!-- Message in delete confirmation dialog for logins -->
|
||||||
<string name="login_deletion_confirmation">Sigur vrei să ștergi aceste date de autentificare?</string>
|
<string name="login_deletion_confirmation">Sigur vrei să ștergi aceste date de autentificare?</string>
|
||||||
<!-- Positive action of a dialog asking to delete -->
|
<!-- Positive action of a dialog asking to delete -->
|
||||||
<string name="dialog_delete_positive">Șterge</string>
|
<string name="dialog_delete_positive">Șterge</string>
|
||||||
|
|
||||||
|
<!-- The saved login options menu description. -->
|
||||||
|
<string name="login_options_menu">Opțiuni de autentificare</string>
|
||||||
|
<!-- The editable text field for a login's web address. -->
|
||||||
|
<string name="saved_login_hostname_description">Câmpul de text editabil pentru adresa web a datelor de autentificare.</string>
|
||||||
|
<!-- The editable text field for a login's username. -->
|
||||||
|
<string name="saved_login_username_description">Câmpul de text editabil pentru numele de utilizator al datelor de autentificare.</string>
|
||||||
|
<!-- The editable text field for a login's password. -->
|
||||||
|
<string name="saved_login_password_description">Câmp de text editabil pentru parola datelor de autentificare.</string>
|
||||||
|
<!-- The button description to save changes to an edited login. -->
|
||||||
|
<string name="save_changes_to_login">Salvează modificările datelor de autentificare.</string>
|
||||||
|
<!-- The button description to discard changes to an edited login. -->
|
||||||
|
<string name="discard_changes">Renunță la modificări</string>
|
||||||
|
<!-- The page title for editing a saved login. -->
|
||||||
|
<string name="edit">Editează</string>
|
||||||
|
<!-- The error message in edit login view when password field is blank. -->
|
||||||
|
<string name="saved_login_password_required">Necesită o parolă</string>
|
||||||
|
<!-- Voice search button content description -->
|
||||||
|
<string name="voice_search_content_description">Căutare vocală</string>
|
||||||
|
<!-- Voice search prompt description displayed after the user presses the voice search button -->
|
||||||
|
<string name="voice_search_explainer">Vorbește acum</string>
|
||||||
|
<!-- The error message in edit login view when a duplicate username exists. -->
|
||||||
|
<string name="saved_login_duplicate">Există un set de date de autentificare cu acest nume de utilizator</string>
|
||||||
|
|
||||||
|
<!-- Synced Tabs -->
|
||||||
|
<!-- Text displayed when user is not logged into a Firefox Account -->
|
||||||
|
<string name="synced_tabs_connect_to_sync_account">Conectare cu un cont Firefox.</string>
|
||||||
|
<!-- Text displayed to ask user to connect another device as no devices found with account -->
|
||||||
|
<string name="synced_tabs_connect_another_device">Conectează alt dispozitiv.</string>
|
||||||
|
<!-- Text displayed asking user to re-authenticate -->
|
||||||
|
<string name="synced_tabs_reauth">Te rugăm să te autentifici din nou.</string>
|
||||||
|
<!-- Text displayed when user has disabled tab syncing in Firefox Sync Account -->
|
||||||
|
<string name="synced_tabs_enable_tab_syncing">Te rugăm să activezi sincronizarea filelor.</string>
|
||||||
|
<!-- Text displayed when user has no tabs that have been synced -->
|
||||||
|
<string name="synced_tabs_no_tabs">Nu ai nicio filă deschisă în Firefox pe celelalte dispozitive.</string>
|
||||||
|
<!-- Text displayed in the synced tabs screen when a user is not signed in to Firefox Sync describing Synced Tabs -->
|
||||||
|
<string name="synced_tabs_sign_in_message">Afișează o listă de file de pe celelalte dispozitive.</string>
|
||||||
|
<!-- Text displayed on a button in the synced tabs screen to link users to sign in when a user is not signed in to Firefox Sync -->
|
||||||
|
<string name="synced_tabs_sign_in_button">Autentifică-te în Sync</string>
|
||||||
|
|
||||||
|
<!-- Top Sites -->
|
||||||
|
<!-- Title text displayed in the dialog when top sites limit is reached. -->
|
||||||
|
<string name="top_sites_max_limit_title">A fost atinsă limita de site-uri de top</string>
|
||||||
|
<!-- Content description text displayed in the dialog when top sites limit is reached. -->
|
||||||
|
<string name="top_sites_max_limit_content">Pentru a adăuga un site de top nou, trebuie să elimini unul existent. Ține degetul pe denumirea site-ului pentru selectare și apoi atinge „Elimină”.</string>
|
||||||
<!-- Confirmation dialog button text when top sites limit is reached. -->
|
<!-- Confirmation dialog button text when top sites limit is reached. -->
|
||||||
<string name="top_sites_max_limit_confirmation_button">Ok, am înțeles</string>
|
<string name="top_sites_max_limit_confirmation_button">Ok, am înțeles</string>
|
||||||
|
|
||||||
|
|
|
@ -84,6 +84,8 @@
|
||||||
|
|
||||||
<declare-styleable name="OnboardingRadioButton">
|
<declare-styleable name="OnboardingRadioButton">
|
||||||
<attr name="onboardingKey" format="reference" />
|
<attr name="onboardingKey" format="reference" />
|
||||||
|
<attr name="onboardingKeyTitle" format="reference" />
|
||||||
|
<attr name="onboardingKeyDescription" format="reference" />
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
<dimen name="radio_button_padding_vertical">12dp</dimen>
|
<dimen name="radio_button_padding_vertical">12dp</dimen>
|
||||||
<dimen name="radio_button_preference_height">48dp</dimen>
|
<dimen name="radio_button_preference_height">48dp</dimen>
|
||||||
<dimen name="radio_button_preference_horizontal">16dp</dimen>
|
<dimen name="radio_button_preference_horizontal">16dp</dimen>
|
||||||
<dimen name="radio_button_preference_drawable_padding">16dp</dimen>
|
<dimen name="radio_button_preference_drawable_padding">24dp</dimen>
|
||||||
<dimen name="radio_button_preference_vertical">12dp</dimen>
|
<dimen name="radio_button_preference_vertical">12dp</dimen>
|
||||||
<dimen name="phone_feature_label_recommended_text_size">14sp</dimen>
|
<dimen name="phone_feature_label_recommended_text_size">14sp</dimen>
|
||||||
<dimen name="site_permissions_exceptions_item_text_size">18sp</dimen>
|
<dimen name="site_permissions_exceptions_item_text_size">18sp</dimen>
|
||||||
|
@ -42,9 +42,10 @@
|
||||||
<dimen name="context_menu_height">48dp</dimen>
|
<dimen name="context_menu_height">48dp</dimen>
|
||||||
<dimen name="context_menu_x_offset">8dp</dimen>
|
<dimen name="context_menu_x_offset">8dp</dimen>
|
||||||
<dimen name="tp_onboarding_width">256dp</dimen>
|
<dimen name="tp_onboarding_width">256dp</dimen>
|
||||||
<dimen name="tp_onboarding_triangle_height">16dp</dimen>
|
<!-- Dimensions for the CFR (Contextual Feature Recommendation) tooltip triangle. -->
|
||||||
<dimen name="tp_onboarding_triangle_width">16dp</dimen>
|
<dimen name="cfr_triangle_height">16dp</dimen>
|
||||||
<dimen name="tp_onboarding_triangle_margin_start">16dp</dimen>
|
<dimen name="cfr_triangle_width">16dp</dimen>
|
||||||
|
<dimen name="cfr_triangle_margin_edge">16dp</dimen>
|
||||||
|
|
||||||
<dimen name="tab_counter_box_width_height">24dp</dimen>
|
<dimen name="tab_counter_box_width_height">24dp</dimen>
|
||||||
|
|
||||||
|
@ -155,6 +156,8 @@
|
||||||
|
|
||||||
<!-- Tabs Tray -->
|
<!-- Tabs Tray -->
|
||||||
<dimen name="tab_tray_top_offset">40dp</dimen>
|
<dimen name="tab_tray_top_offset">40dp</dimen>
|
||||||
|
<dimen name="tab_tray_thumbnail_width">92dp</dimen>
|
||||||
|
<dimen name="tab_tray_thumbnail_height">69dp</dimen>
|
||||||
|
|
||||||
<!-- Saved Logins Fragment -->
|
<!-- Saved Logins Fragment -->
|
||||||
<dimen name="saved_logins_sort_menu_dropdown_chevron_icon_margin_start">10dp</dimen>
|
<dimen name="saved_logins_sort_menu_dropdown_chevron_icon_margin_start">10dp</dimen>
|
||||||
|
|
|
@ -33,4 +33,7 @@
|
||||||
<!-- Label for the secret settings preference -->
|
<!-- Label for the secret settings preference -->
|
||||||
<string name="preferences_debug_settings">Secret Settings</string>
|
<string name="preferences_debug_settings">Secret Settings</string>
|
||||||
<string name="preferences_debug_settings_enable_tab_tray">Use New Tab Tray</string>
|
<string name="preferences_debug_settings_enable_tab_tray">Use New Tab Tray</string>
|
||||||
|
|
||||||
|
<!-- Content description (not visible, for screen readers etc.) used to announce [LinkTextView]. -->
|
||||||
|
<string name="link_text_view_type_announcement" translatable="false">link</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -1432,6 +1432,4 @@
|
||||||
<string name="top_sites_max_limit_content">To add a new top site, remove one. Long press the site and select remove.</string>
|
<string name="top_sites_max_limit_content">To add a new top site, remove one. Long press the site and select remove.</string>
|
||||||
<!-- Confirmation dialog button text when top sites limit is reached. -->
|
<!-- Confirmation dialog button text when top sites limit is reached. -->
|
||||||
<string name="top_sites_max_limit_confirmation_button">OK, Got It</string>
|
<string name="top_sites_max_limit_confirmation_button">OK, Got It</string>
|
||||||
<!-- Content description (not visible, for screen readers etc.) used to announce [LinkTextView]. -->
|
|
||||||
<string name="link_text_view_type_announcement">link</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -6,6 +6,8 @@ package org.mozilla.fenix
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.spyk
|
||||||
import mozilla.components.support.test.robolectric.testContext
|
import mozilla.components.support.test.robolectric.testContext
|
||||||
import mozilla.components.support.utils.toSafeIntent
|
import mozilla.components.support.utils.toSafeIntent
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
|
@ -13,6 +15,7 @@ import org.junit.Assert.assertFalse
|
||||||
import org.junit.Assert.assertNotEquals
|
import org.junit.Assert.assertNotEquals
|
||||||
import org.junit.Assert.assertNull
|
import org.junit.Assert.assertNull
|
||||||
import org.junit.Assert.assertTrue
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.mozilla.fenix.HomeActivity.Companion.PRIVATE_BROWSING_MODE
|
import org.mozilla.fenix.HomeActivity.Companion.PRIVATE_BROWSING_MODE
|
||||||
|
@ -24,10 +27,17 @@ import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||||
@RunWith(FenixRobolectricTestRunner::class)
|
@RunWith(FenixRobolectricTestRunner::class)
|
||||||
class HomeActivityTest {
|
class HomeActivityTest {
|
||||||
|
|
||||||
|
private lateinit var activity: HomeActivity
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
activity = spyk(HomeActivity())
|
||||||
|
|
||||||
|
every { activity.applicationContext } returns testContext
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun getIntentSource() {
|
fun getIntentSource() {
|
||||||
val activity = HomeActivity()
|
|
||||||
|
|
||||||
val launcherIntent = Intent(Intent.ACTION_MAIN).apply {
|
val launcherIntent = Intent(Intent.ACTION_MAIN).apply {
|
||||||
addCategory(Intent.CATEGORY_LAUNCHER)
|
addCategory(Intent.CATEGORY_LAUNCHER)
|
||||||
}.toSafeIntent()
|
}.toSafeIntent()
|
||||||
|
@ -42,8 +52,6 @@ class HomeActivityTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `getModeFromIntentOrLastKnown returns mode from settings when intent does not set`() {
|
fun `getModeFromIntentOrLastKnown returns mode from settings when intent does not set`() {
|
||||||
val activity = HomeActivity()
|
|
||||||
|
|
||||||
testContext.settings().lastKnownMode = BrowsingMode.Private
|
testContext.settings().lastKnownMode = BrowsingMode.Private
|
||||||
|
|
||||||
assertEquals(testContext.settings().lastKnownMode, activity.getModeFromIntentOrLastKnown(null))
|
assertEquals(testContext.settings().lastKnownMode, activity.getModeFromIntentOrLastKnown(null))
|
||||||
|
@ -51,8 +59,6 @@ class HomeActivityTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `getModeFromIntentOrLastKnown returns mode from intent when set`() {
|
fun `getModeFromIntentOrLastKnown returns mode from intent when set`() {
|
||||||
val activity = HomeActivity()
|
|
||||||
|
|
||||||
testContext.settings().lastKnownMode = BrowsingMode.Normal
|
testContext.settings().lastKnownMode = BrowsingMode.Normal
|
||||||
|
|
||||||
val intent = Intent()
|
val intent = Intent()
|
||||||
|
@ -64,21 +70,16 @@ class HomeActivityTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `isActivityColdStarted returns true for null savedInstanceState and not launched from history`() {
|
fun `isActivityColdStarted returns true for null savedInstanceState and not launched from history`() {
|
||||||
val activity = HomeActivity()
|
|
||||||
|
|
||||||
assertTrue(activity.isActivityColdStarted(Intent(), null))
|
assertTrue(activity.isActivityColdStarted(Intent(), null))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `isActivityColdStarted returns false for valid savedInstanceState and not launched from history`() {
|
fun `isActivityColdStarted returns false for valid savedInstanceState and not launched from history`() {
|
||||||
val activity = HomeActivity()
|
|
||||||
|
|
||||||
assertFalse(activity.isActivityColdStarted(Intent(), Bundle()))
|
assertFalse(activity.isActivityColdStarted(Intent(), Bundle()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `isActivityColdStarted returns false for null savedInstanceState and launched from history`() {
|
fun `isActivityColdStarted returns false for null savedInstanceState and launched from history`() {
|
||||||
val activity = HomeActivity()
|
|
||||||
val startingIntent = Intent().apply {
|
val startingIntent = Intent().apply {
|
||||||
flags = flags or Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
|
flags = flags or Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
|
||||||
}
|
}
|
||||||
|
@ -88,7 +89,6 @@ class HomeActivityTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `isActivityColdStarted returns false for null savedInstanceState and not launched from history`() {
|
fun `isActivityColdStarted returns false for null savedInstanceState and not launched from history`() {
|
||||||
val activity = HomeActivity()
|
|
||||||
val startingIntent = Intent().apply {
|
val startingIntent = Intent().apply {
|
||||||
flags = flags or Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
|
flags = flags or Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,14 +5,19 @@
|
||||||
package org.mozilla.fenix.browser.browsingmode
|
package org.mozilla.fenix.browser.browsingmode
|
||||||
|
|
||||||
import io.mockk.MockKAnnotations
|
import io.mockk.MockKAnnotations
|
||||||
|
import io.mockk.Runs
|
||||||
|
import io.mockk.every
|
||||||
import io.mockk.impl.annotations.MockK
|
import io.mockk.impl.annotations.MockK
|
||||||
|
import io.mockk.just
|
||||||
import io.mockk.verify
|
import io.mockk.verify
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import org.mozilla.fenix.utils.Settings
|
||||||
|
|
||||||
class DefaultBrowsingModeManagerTest {
|
class DefaultBrowsingModeManagerTest {
|
||||||
|
|
||||||
|
@MockK lateinit var settings: Settings
|
||||||
@MockK(relaxed = true) lateinit var callback: (BrowsingMode) -> Unit
|
@MockK(relaxed = true) lateinit var callback: (BrowsingMode) -> Unit
|
||||||
lateinit var manager: BrowsingModeManager
|
lateinit var manager: BrowsingModeManager
|
||||||
|
|
||||||
|
@ -21,7 +26,9 @@ class DefaultBrowsingModeManagerTest {
|
||||||
@Before
|
@Before
|
||||||
fun before() {
|
fun before() {
|
||||||
MockKAnnotations.init(this)
|
MockKAnnotations.init(this)
|
||||||
manager = DefaultBrowsingModeManager(initMode, callback)
|
|
||||||
|
manager = DefaultBrowsingModeManager(initMode, settings, callback)
|
||||||
|
every { settings.lastKnownMode = any() } just Runs
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -46,8 +53,10 @@ class DefaultBrowsingModeManagerTest {
|
||||||
|
|
||||||
manager.mode = BrowsingMode.Private
|
manager.mode = BrowsingMode.Private
|
||||||
assertEquals(BrowsingMode.Private, manager.mode)
|
assertEquals(BrowsingMode.Private, manager.mode)
|
||||||
|
verify { settings.lastKnownMode = BrowsingMode.Private }
|
||||||
|
|
||||||
manager.mode = BrowsingMode.Normal
|
manager.mode = BrowsingMode.Normal
|
||||||
assertEquals(BrowsingMode.Normal, manager.mode)
|
assertEquals(BrowsingMode.Normal, manager.mode)
|
||||||
|
verify { settings.lastKnownMode = BrowsingMode.Normal }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,43 +4,43 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.components
|
package org.mozilla.fenix.components
|
||||||
|
|
||||||
import android.content.Context
|
import io.mockk.MockKAnnotations
|
||||||
import io.mockk.Runs
|
import io.mockk.Runs
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
|
import io.mockk.impl.annotations.MockK
|
||||||
import io.mockk.just
|
import io.mockk.just
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import io.mockk.verify
|
import io.mockk.verify
|
||||||
import mozilla.components.concept.sync.AccountObserver
|
import mozilla.components.concept.sync.AccountObserver
|
||||||
import mozilla.components.concept.sync.AuthType
|
import mozilla.components.concept.sync.AuthType
|
||||||
import mozilla.components.concept.sync.OAuthAccount
|
import mozilla.components.concept.sync.OAuthAccount
|
||||||
import mozilla.components.service.fxa.DeviceConfig
|
|
||||||
import mozilla.components.service.fxa.ServerConfig
|
|
||||||
import mozilla.components.service.fxa.SyncConfig
|
|
||||||
import mozilla.components.service.fxa.manager.FxaAccountManager
|
|
||||||
import mozilla.components.support.base.observer.ObserverRegistry
|
import mozilla.components.support.base.observer.ObserverRegistry
|
||||||
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
import org.mozilla.fenix.components.metrics.MetricController
|
import org.mozilla.fenix.components.metrics.MetricController
|
||||||
|
import org.mozilla.fenix.utils.Settings
|
||||||
|
|
||||||
class BackgroundServicesTest {
|
class BackgroundServicesTest {
|
||||||
class TestableBackgroundServices(
|
|
||||||
val context: Context
|
@MockK private lateinit var metrics: MetricController
|
||||||
) : BackgroundServices(context, mockk(), mockk(), mockk(), mockk(), mockk(), mockk()) {
|
@MockK private lateinit var settings: Settings
|
||||||
override fun makeAccountManager(
|
|
||||||
context: Context,
|
private lateinit var observer: TelemetryAccountObserver
|
||||||
serverConfig: ServerConfig,
|
private lateinit var registry: ObserverRegistry<AccountObserver>
|
||||||
deviceConfig: DeviceConfig,
|
|
||||||
syncConfig: SyncConfig?
|
@Before
|
||||||
) = mockk<FxaAccountManager>(relaxed = true)
|
fun setup() {
|
||||||
|
MockKAnnotations.init(this)
|
||||||
|
every { metrics.track(any()) } just Runs
|
||||||
|
every { settings.fxaSignedIn = any() } just Runs
|
||||||
|
|
||||||
|
observer = TelemetryAccountObserver(mockk(relaxed = true), metrics)
|
||||||
|
registry = ObserverRegistry<AccountObserver>().apply { register(observer) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `telemetry account observer`() {
|
fun `telemetry account observer`() {
|
||||||
val metrics = mockk<MetricController>()
|
|
||||||
every { metrics.track(any()) } just Runs
|
|
||||||
val observer = TelemetryAccountObserver(mockk(relaxed = true), metrics)
|
|
||||||
val registry = ObserverRegistry<AccountObserver>()
|
|
||||||
registry.register(observer)
|
|
||||||
val account = mockk<OAuthAccount>()
|
val account = mockk<OAuthAccount>()
|
||||||
|
|
||||||
// Sign-in
|
// Sign-in
|
||||||
|
|
|
@ -7,6 +7,7 @@ package org.mozilla.fenix.components
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import org.mozilla.fenix.utils.ClipboardHandler
|
import org.mozilla.fenix.utils.ClipboardHandler
|
||||||
|
import org.mozilla.fenix.utils.Settings
|
||||||
|
|
||||||
class TestComponents(private val context: Context) : Components(context) {
|
class TestComponents(private val context: Context) : Components(context) {
|
||||||
override val backgroundServices by lazy {
|
override val backgroundServices by lazy {
|
||||||
|
@ -29,4 +30,6 @@ class TestComponents(private val context: Context) : Components(context) {
|
||||||
override val analytics by lazy { Analytics(context) }
|
override val analytics by lazy { Analytics(context) }
|
||||||
|
|
||||||
override val clipboardHandler by lazy { ClipboardHandler(context) }
|
override val clipboardHandler by lazy { ClipboardHandler(context) }
|
||||||
|
|
||||||
|
override val settings by lazy { mockk<Settings>(relaxed = true) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -543,7 +543,10 @@ class DefaultBrowserToolbarControllerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun handleToolbarNewTabPress() = runBlockingTest {
|
fun handleToolbarNewTabPress() = runBlockingTest {
|
||||||
val browsingModeManager: BrowsingModeManager = DefaultBrowsingModeManager(BrowsingMode.Private) {}
|
val browsingModeManager: BrowsingModeManager = DefaultBrowsingModeManager(
|
||||||
|
BrowsingMode.Private,
|
||||||
|
mockk(relaxed = true)
|
||||||
|
) {}
|
||||||
val item = TabCounterMenuItem.NewTab(false)
|
val item = TabCounterMenuItem.NewTab(false)
|
||||||
|
|
||||||
every { activity.browsingModeManager } returns browsingModeManager
|
every { activity.browsingModeManager } returns browsingModeManager
|
||||||
|
@ -556,7 +559,10 @@ class DefaultBrowserToolbarControllerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun handleToolbarNewPrivateTabPress() = runBlockingTest {
|
fun handleToolbarNewPrivateTabPress() = runBlockingTest {
|
||||||
val browsingModeManager: BrowsingModeManager = DefaultBrowsingModeManager(BrowsingMode.Normal) {}
|
val browsingModeManager: BrowsingModeManager = DefaultBrowsingModeManager(
|
||||||
|
BrowsingMode.Normal,
|
||||||
|
mockk(relaxed = true)
|
||||||
|
) {}
|
||||||
val item = TabCounterMenuItem.NewTab(true)
|
val item = TabCounterMenuItem.NewTab(true)
|
||||||
|
|
||||||
every { activity.browsingModeManager } returns browsingModeManager
|
every { activity.browsingModeManager } returns browsingModeManager
|
||||||
|
|
|
@ -7,15 +7,14 @@ package org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.mockk
|
|
||||||
import kotlinx.android.synthetic.main.onboarding_toolbar_position_picker.view.*
|
import kotlinx.android.synthetic.main.onboarding_toolbar_position_picker.view.*
|
||||||
import mozilla.components.support.test.robolectric.testContext
|
import mozilla.components.support.test.robolectric.testContext
|
||||||
import org.junit.After
|
|
||||||
import org.junit.Assert.assertFalse
|
import org.junit.Assert.assertFalse
|
||||||
import org.junit.Assert.assertTrue
|
import org.junit.Assert.assertTrue
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||||
import org.mozilla.fenix.utils.Settings
|
import org.mozilla.fenix.utils.Settings
|
||||||
|
|
||||||
|
@ -27,16 +26,10 @@ class OnboardingToolbarPositionPickerViewHolderTest {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setup() {
|
fun setup() {
|
||||||
|
val components = testContext.components
|
||||||
view = LayoutInflater.from(testContext)
|
view = LayoutInflater.from(testContext)
|
||||||
.inflate(OnboardingToolbarPositionPickerViewHolder.LAYOUT_ID, null)
|
.inflate(OnboardingToolbarPositionPickerViewHolder.LAYOUT_ID, null)
|
||||||
settings = mockk(relaxed = true)
|
settings = components.settings
|
||||||
|
|
||||||
Settings.instance = settings
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
fun teardown() {
|
|
||||||
Settings.instance = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -0,0 +1,183 @@
|
||||||
|
/* 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.push
|
||||||
|
|
||||||
|
import android.util.Base64
|
||||||
|
import io.mockk.Called
|
||||||
|
import io.mockk.CapturingSlot
|
||||||
|
import io.mockk.MockKAnnotations
|
||||||
|
import io.mockk.Runs
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.impl.annotations.MockK
|
||||||
|
import io.mockk.just
|
||||||
|
import io.mockk.mockk
|
||||||
|
import io.mockk.mockkStatic
|
||||||
|
import io.mockk.slot
|
||||||
|
import io.mockk.unmockkStatic
|
||||||
|
import io.mockk.verify
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.test.TestCoroutineScope
|
||||||
|
import kotlinx.coroutines.test.runBlockingTest
|
||||||
|
import mozilla.components.concept.engine.Engine
|
||||||
|
import mozilla.components.concept.engine.webpush.WebPushDelegate
|
||||||
|
import mozilla.components.concept.engine.webpush.WebPushHandler
|
||||||
|
import mozilla.components.concept.engine.webpush.WebPushSubscription
|
||||||
|
import mozilla.components.feature.push.AutoPushFeature
|
||||||
|
import mozilla.components.feature.push.AutoPushSubscription
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
|
class WebPushEngineIntegrationTest {
|
||||||
|
|
||||||
|
private val scope = TestCoroutineScope()
|
||||||
|
@MockK private lateinit var engine: Engine
|
||||||
|
@MockK private lateinit var pushFeature: AutoPushFeature
|
||||||
|
@MockK(relaxed = true) private lateinit var handler: WebPushHandler
|
||||||
|
private lateinit var delegate: CapturingSlot<WebPushDelegate>
|
||||||
|
private lateinit var integration: WebPushEngineIntegration
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
MockKAnnotations.init(this)
|
||||||
|
mockkStatic(Base64::class)
|
||||||
|
delegate = slot()
|
||||||
|
|
||||||
|
every { engine.registerWebPushDelegate(capture(delegate)) } returns handler
|
||||||
|
every { pushFeature.register(any()) } just Runs
|
||||||
|
every { pushFeature.unregister(any()) } just Runs
|
||||||
|
every { Base64.decode(any<ByteArray>(), any()) } answers { firstArg() }
|
||||||
|
|
||||||
|
integration = WebPushEngineIntegration(engine, pushFeature, scope)
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun teardown() {
|
||||||
|
unmockkStatic(Base64::class)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `methods are no-op before calling start`() = scope.runBlockingTest {
|
||||||
|
integration.onMessageReceived("push", null)
|
||||||
|
integration.onSubscriptionChanged("push")
|
||||||
|
verify { handler wasNot Called }
|
||||||
|
|
||||||
|
integration.start()
|
||||||
|
|
||||||
|
integration.onMessageReceived("push", null)
|
||||||
|
verify { handler.onPushMessage("push", null) }
|
||||||
|
|
||||||
|
integration.onSubscriptionChanged("push")
|
||||||
|
verify { handler.onSubscriptionChanged("push") }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `start and stop register and unregister pushFeature`() {
|
||||||
|
integration.start()
|
||||||
|
verify { pushFeature.register(integration) }
|
||||||
|
|
||||||
|
integration.stop()
|
||||||
|
verify { pushFeature.unregister(integration) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `delegate calls getSubscription`() {
|
||||||
|
integration.start()
|
||||||
|
val slot = slot<(AutoPushSubscription?) -> Unit>()
|
||||||
|
every { pushFeature.getSubscription("scope", block = capture(slot)) } just Runs
|
||||||
|
|
||||||
|
val onSubscription = mockk<(WebPushSubscription?) -> Unit>(relaxed = true)
|
||||||
|
delegate.captured.onGetSubscription("scope", onSubscription)
|
||||||
|
|
||||||
|
verify { onSubscription wasNot Called }
|
||||||
|
slot.captured(AutoPushSubscription(
|
||||||
|
scope = "scope",
|
||||||
|
publicKey = "abc",
|
||||||
|
endpoint = "def",
|
||||||
|
authKey = "xyz",
|
||||||
|
appServerKey = null
|
||||||
|
))
|
||||||
|
|
||||||
|
verify {
|
||||||
|
onSubscription(
|
||||||
|
WebPushSubscription(
|
||||||
|
scope = "scope",
|
||||||
|
publicKey = "abc".toByteArray(),
|
||||||
|
endpoint = "def",
|
||||||
|
authSecret = "xyz".toByteArray(),
|
||||||
|
appServerKey = null
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `delegate calls subscribe`() {
|
||||||
|
integration.start()
|
||||||
|
val onSubscribeError = slot<() -> Unit>()
|
||||||
|
val onSubscribe = slot<(AutoPushSubscription?) -> Unit>()
|
||||||
|
every {
|
||||||
|
pushFeature.subscribe(
|
||||||
|
scope = "scope",
|
||||||
|
appServerKey = null,
|
||||||
|
onSubscribeError = capture(onSubscribeError),
|
||||||
|
onSubscribe = capture(onSubscribe)
|
||||||
|
)
|
||||||
|
} just Runs
|
||||||
|
|
||||||
|
val onSubscription = mockk<(WebPushSubscription?) -> Unit>(relaxed = true)
|
||||||
|
delegate.captured.onSubscribe("scope", null, onSubscription)
|
||||||
|
|
||||||
|
verify { onSubscription wasNot Called }
|
||||||
|
|
||||||
|
onSubscribeError.captured()
|
||||||
|
verify { onSubscription(null) }
|
||||||
|
|
||||||
|
onSubscribe.captured(AutoPushSubscription(
|
||||||
|
scope = "scope",
|
||||||
|
publicKey = "abc",
|
||||||
|
endpoint = "def",
|
||||||
|
authKey = "xyz",
|
||||||
|
appServerKey = null
|
||||||
|
))
|
||||||
|
verify {
|
||||||
|
onSubscription(
|
||||||
|
WebPushSubscription(
|
||||||
|
scope = "scope",
|
||||||
|
publicKey = "abc".toByteArray(),
|
||||||
|
endpoint = "def",
|
||||||
|
authSecret = "xyz".toByteArray(),
|
||||||
|
appServerKey = null
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `delegate calls unsubscribe`() {
|
||||||
|
integration.start()
|
||||||
|
val onUnsubscribeError = slot<() -> Unit>()
|
||||||
|
val onUnsubscribe = slot<(Boolean) -> Unit>()
|
||||||
|
every {
|
||||||
|
pushFeature.unsubscribe(
|
||||||
|
scope = "scope",
|
||||||
|
onUnsubscribeError = capture(onUnsubscribeError),
|
||||||
|
onUnsubscribe = capture(onUnsubscribe)
|
||||||
|
)
|
||||||
|
} just Runs
|
||||||
|
|
||||||
|
val onUnsubscription = mockk<(Boolean) -> Unit>(relaxed = true)
|
||||||
|
delegate.captured.onUnsubscribe("scope", onUnsubscription)
|
||||||
|
|
||||||
|
verify { onUnsubscription wasNot Called }
|
||||||
|
|
||||||
|
onUnsubscribeError.captured()
|
||||||
|
verify { onUnsubscription(false) }
|
||||||
|
|
||||||
|
onUnsubscribe.captured(true)
|
||||||
|
verify { onUnsubscription(true) }
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,7 +35,6 @@ import org.mozilla.fenix.ext.settings
|
||||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||||
import org.mozilla.fenix.settings.SupportUtils
|
import org.mozilla.fenix.settings.SupportUtils
|
||||||
import org.mozilla.fenix.utils.Settings
|
import org.mozilla.fenix.utils.Settings
|
||||||
import org.mozilla.fenix.whatsnew.clear
|
|
||||||
|
|
||||||
@ExperimentalCoroutinesApi
|
@ExperimentalCoroutinesApi
|
||||||
@RunWith(FenixRobolectricTestRunner::class)
|
@RunWith(FenixRobolectricTestRunner::class)
|
||||||
|
@ -48,10 +47,10 @@ class DefaultSearchControllerTest {
|
||||||
private val searchEngine: SearchEngine = mockk(relaxed = true)
|
private val searchEngine: SearchEngine = mockk(relaxed = true)
|
||||||
private val metrics: MetricController = mockk(relaxed = true)
|
private val metrics: MetricController = mockk(relaxed = true)
|
||||||
private val sessionManager: SessionManager = mockk(relaxed = true)
|
private val sessionManager: SessionManager = mockk(relaxed = true)
|
||||||
|
private val settings: Settings = mockk(relaxed = true)
|
||||||
private val clearToolbarFocus: (() -> Unit) = mockk(relaxed = true)
|
private val clearToolbarFocus: (() -> Unit) = mockk(relaxed = true)
|
||||||
|
|
||||||
private lateinit var controller: DefaultSearchController
|
private lateinit var controller: DefaultSearchController
|
||||||
private lateinit var settings: Settings
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
|
@ -60,6 +59,7 @@ class DefaultSearchControllerTest {
|
||||||
every { store.state.searchEngineSource.searchEngine } returns searchEngine
|
every { store.state.searchEngineSource.searchEngine } returns searchEngine
|
||||||
every { activity.metrics } returns metrics
|
every { activity.metrics } returns metrics
|
||||||
every { activity.components.core.sessionManager } returns sessionManager
|
every { activity.components.core.sessionManager } returns sessionManager
|
||||||
|
every { activity.components.settings } returns settings
|
||||||
|
|
||||||
controller = DefaultSearchController(
|
controller = DefaultSearchController(
|
||||||
activity = activity,
|
activity = activity,
|
||||||
|
@ -67,8 +67,6 @@ class DefaultSearchControllerTest {
|
||||||
navController = navController,
|
navController = navController,
|
||||||
clearToolbarFocus = clearToolbarFocus
|
clearToolbarFocus = clearToolbarFocus
|
||||||
)
|
)
|
||||||
|
|
||||||
settings = testContext.settings().apply { testContext.settings().clear() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -154,10 +152,7 @@ class DefaultSearchControllerTest {
|
||||||
@Test
|
@Test
|
||||||
fun `show search shortcuts when setting enabled AND query empty`() {
|
fun `show search shortcuts when setting enabled AND query empty`() {
|
||||||
val text = ""
|
val text = ""
|
||||||
testContext.settings().preferences
|
every { settings.shouldShowSearchShortcuts } returns true
|
||||||
.edit()
|
|
||||||
.putBoolean(testContext.getString(R.string.pref_key_show_search_shortcuts), true)
|
|
||||||
.apply()
|
|
||||||
|
|
||||||
controller.handleTextChanged(text)
|
controller.handleTextChanged(text)
|
||||||
|
|
||||||
|
@ -168,10 +163,7 @@ class DefaultSearchControllerTest {
|
||||||
fun `show search shortcuts when setting enabled AND query equals url`() {
|
fun `show search shortcuts when setting enabled AND query equals url`() {
|
||||||
val text = "mozilla.org"
|
val text = "mozilla.org"
|
||||||
every { store.state.url } returns "mozilla.org"
|
every { store.state.url } returns "mozilla.org"
|
||||||
testContext.settings().preferences
|
every { settings.shouldShowSearchShortcuts } returns true
|
||||||
.edit()
|
|
||||||
.putBoolean(testContext.getString(R.string.pref_key_show_search_shortcuts), true)
|
|
||||||
.apply()
|
|
||||||
|
|
||||||
controller.handleTextChanged(text)
|
controller.handleTextChanged(text)
|
||||||
|
|
||||||
|
@ -189,10 +181,7 @@ class DefaultSearchControllerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `do not show search shortcuts when setting disabled AND query empty AND url not matching query`() {
|
fun `do not show search shortcuts when setting disabled AND query empty AND url not matching query`() {
|
||||||
testContext.settings().preferences
|
every { settings.shouldShowSearchShortcuts } returns false
|
||||||
.edit()
|
|
||||||
.putBoolean(testContext.getString(R.string.pref_key_show_search_shortcuts), false)
|
|
||||||
.apply()
|
|
||||||
|
|
||||||
assertFalse(testContext.settings().shouldShowSearchShortcuts)
|
assertFalse(testContext.settings().shouldShowSearchShortcuts)
|
||||||
|
|
||||||
|
@ -205,10 +194,7 @@ class DefaultSearchControllerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `do not show search shortcuts when setting disabled AND query non-empty`() {
|
fun `do not show search shortcuts when setting disabled AND query non-empty`() {
|
||||||
testContext.settings().preferences
|
every { settings.shouldShowSearchShortcuts } returns false
|
||||||
.edit()
|
|
||||||
.putBoolean(testContext.getString(R.string.pref_key_show_search_shortcuts), false)
|
|
||||||
.apply()
|
|
||||||
|
|
||||||
assertFalse(testContext.settings().shouldShowSearchShortcuts)
|
assertFalse(testContext.settings().shouldShowSearchShortcuts)
|
||||||
|
|
||||||
|
|
|
@ -6,33 +6,58 @@ package org.mozilla.fenix.search.toolbar
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.appcompat.view.ContextThemeWrapper
|
import androidx.appcompat.view.ContextThemeWrapper
|
||||||
|
import androidx.core.graphics.drawable.toBitmap
|
||||||
import io.mockk.MockKAnnotations
|
import io.mockk.MockKAnnotations
|
||||||
import io.mockk.Runs
|
import io.mockk.Runs
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.impl.annotations.MockK
|
import io.mockk.impl.annotations.MockK
|
||||||
import io.mockk.just
|
import io.mockk.just
|
||||||
|
import io.mockk.mockk
|
||||||
import io.mockk.slot
|
import io.mockk.slot
|
||||||
import io.mockk.spyk
|
import io.mockk.spyk
|
||||||
import io.mockk.verify
|
import io.mockk.verify
|
||||||
import mozilla.components.browser.toolbar.BrowserToolbar
|
import mozilla.components.browser.toolbar.BrowserToolbar
|
||||||
|
import mozilla.components.browser.toolbar.edit.EditToolbar
|
||||||
import mozilla.components.concept.engine.Engine
|
import mozilla.components.concept.engine.Engine
|
||||||
import mozilla.components.concept.toolbar.Toolbar
|
import mozilla.components.concept.toolbar.Toolbar
|
||||||
import mozilla.components.support.test.robolectric.testContext
|
import mozilla.components.support.test.robolectric.testContext
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Assert.assertFalse
|
import org.junit.Assert.assertFalse
|
||||||
import org.junit.Assert.assertTrue
|
import org.junit.Assert.assertTrue
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||||
|
import org.mozilla.fenix.search.SearchEngineSource
|
||||||
|
import org.mozilla.fenix.search.SearchFragmentState
|
||||||
|
|
||||||
@RunWith(FenixRobolectricTestRunner::class)
|
@RunWith(FenixRobolectricTestRunner::class)
|
||||||
class ToolbarViewTest {
|
class ToolbarViewTest {
|
||||||
|
|
||||||
@MockK(relaxed = true) private lateinit var interactor: ToolbarInteractor
|
@MockK(relaxed = true) private lateinit var interactor: ToolbarInteractor
|
||||||
@MockK private lateinit var engine: Engine
|
@MockK private lateinit var engine: Engine
|
||||||
private lateinit var context: Context
|
private lateinit var context: Context
|
||||||
private lateinit var toolbar: BrowserToolbar
|
private lateinit var toolbar: BrowserToolbar
|
||||||
|
private val defaultState: SearchFragmentState = SearchFragmentState(
|
||||||
|
tabId = null,
|
||||||
|
url = "",
|
||||||
|
searchTerms = "",
|
||||||
|
query = "",
|
||||||
|
searchEngineSource = SearchEngineSource.Default(mockk {
|
||||||
|
every { name } returns "Search Engine"
|
||||||
|
every { icon } returns testContext.getDrawable(R.drawable.ic_search)!!.toBitmap()
|
||||||
|
}),
|
||||||
|
defaultEngineSource = mockk(relaxed = true),
|
||||||
|
showSearchSuggestionsHint = false,
|
||||||
|
showSearchSuggestions = false,
|
||||||
|
showSearchShortcuts = false,
|
||||||
|
areShortcutsAvailable = true,
|
||||||
|
showClipboardSuggestions = false,
|
||||||
|
showHistorySuggestions = false,
|
||||||
|
showBookmarkSuggestions = false,
|
||||||
|
searchAccessPoint = Event.PerformedSearch.SearchAccessPoint.NONE
|
||||||
|
)
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setup() {
|
fun setup() {
|
||||||
|
@ -72,6 +97,69 @@ class ToolbarViewTest {
|
||||||
assertTrue(toolbar.private)
|
assertTrue(toolbar.private)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `View gets initialized only once`() {
|
||||||
|
val view = buildToolbarView(false)
|
||||||
|
assertFalse(view.isInitialized)
|
||||||
|
|
||||||
|
view.update(defaultState)
|
||||||
|
view.update(defaultState)
|
||||||
|
view.update(defaultState)
|
||||||
|
|
||||||
|
verify(exactly = 1) { toolbar.url = any() }
|
||||||
|
verify(exactly = 1) { toolbar.setSearchTerms(any()) }
|
||||||
|
verify(exactly = 1) { interactor.onTextChanged(any()) }
|
||||||
|
// editMode gets called when the view is initialized. So it is called twice in this test
|
||||||
|
verify(exactly = 2) { toolbar.editMode() }
|
||||||
|
|
||||||
|
assertTrue(view.isInitialized)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `URL gets set to the states query`() {
|
||||||
|
val toolbarView = buildToolbarView(false)
|
||||||
|
toolbarView.update(defaultState.copy(query = "Query"))
|
||||||
|
|
||||||
|
assertEquals("Query", toolbarView.view.url)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `URL gets set to the states pastedText if exists`() {
|
||||||
|
val toolbarView = buildToolbarView(false)
|
||||||
|
toolbarView.update(defaultState.copy(query = "Query", pastedText = "Pasted"))
|
||||||
|
|
||||||
|
assertEquals("Pasted", toolbarView.view.url)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `searchTerms get set if pastedText is null or empty`() {
|
||||||
|
val toolbarView = buildToolbarView(false)
|
||||||
|
toolbarView.update(defaultState.copy(query = "Query", pastedText = "", searchTerms = "Search Terms"))
|
||||||
|
|
||||||
|
verify { toolbar.setSearchTerms("Search Terms") }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `searchTerms don't get set if pastedText has a value`() {
|
||||||
|
val toolbarView = buildToolbarView(false)
|
||||||
|
toolbarView.update(
|
||||||
|
defaultState.copy(query = "Query", pastedText = "PastedText", searchTerms = "Search Terms")
|
||||||
|
)
|
||||||
|
|
||||||
|
verify(exactly = 0) { toolbar.setSearchTerms("Search Terms") }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `searchEngine name and icon get set on update`() {
|
||||||
|
val editToolbar: EditToolbar = mockk(relaxed = true)
|
||||||
|
every { toolbar.edit } returns editToolbar
|
||||||
|
|
||||||
|
val toolbarView = buildToolbarView(false)
|
||||||
|
toolbarView.update(defaultState)
|
||||||
|
|
||||||
|
verify { editToolbar.setIcon(any(), "Search Engine") }
|
||||||
|
}
|
||||||
|
|
||||||
private fun buildToolbarView(isPrivate: Boolean) = ToolbarView(
|
private fun buildToolbarView(isPrivate: Boolean) = ToolbarView(
|
||||||
context,
|
context,
|
||||||
interactor,
|
interactor,
|
||||||
|
|
|
@ -16,7 +16,6 @@ import kotlinx.coroutines.test.runBlockingTest
|
||||||
import mozilla.components.browser.storage.sync.PlacesHistoryStorage
|
import mozilla.components.browser.storage.sync.PlacesHistoryStorage
|
||||||
import mozilla.components.concept.engine.Engine
|
import mozilla.components.concept.engine.Engine
|
||||||
import mozilla.components.feature.tabs.TabsUseCases
|
import mozilla.components.feature.tabs.TabsUseCases
|
||||||
import mozilla.components.support.test.robolectric.testContext
|
|
||||||
import mozilla.components.support.test.rule.MainCoroutineRule
|
import mozilla.components.support.test.rule.MainCoroutineRule
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Ignore
|
import org.junit.Ignore
|
||||||
|
@ -26,7 +25,6 @@ import org.junit.runner.RunWith
|
||||||
import org.mozilla.fenix.HomeActivity
|
import org.mozilla.fenix.HomeActivity
|
||||||
import org.mozilla.fenix.components.FenixSnackbar
|
import org.mozilla.fenix.components.FenixSnackbar
|
||||||
import org.mozilla.fenix.components.PermissionStorage
|
import org.mozilla.fenix.components.PermissionStorage
|
||||||
import org.mozilla.fenix.ext.clearAndCommit
|
|
||||||
import org.mozilla.fenix.ext.components
|
import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||||
import org.mozilla.fenix.utils.Settings
|
import org.mozilla.fenix.utils.Settings
|
||||||
|
@ -38,8 +36,8 @@ class DeleteAndQuitTest {
|
||||||
@get:Rule
|
@get:Rule
|
||||||
val coroutinesTestRule = MainCoroutineRule(TestCoroutineDispatcher())
|
val coroutinesTestRule = MainCoroutineRule(TestCoroutineDispatcher())
|
||||||
|
|
||||||
private var activity: HomeActivity = mockk(relaxed = true)
|
private val activity: HomeActivity = mockk(relaxed = true)
|
||||||
lateinit var settings: Settings
|
private val settings: Settings = mockk(relaxed = true)
|
||||||
private val tabUseCases: TabsUseCases = mockk(relaxed = true)
|
private val tabUseCases: TabsUseCases = mockk(relaxed = true)
|
||||||
private val historyStorage: PlacesHistoryStorage = mockk(relaxed = true)
|
private val historyStorage: PlacesHistoryStorage = mockk(relaxed = true)
|
||||||
private val permissionStorage: PermissionStorage = mockk(relaxed = true)
|
private val permissionStorage: PermissionStorage = mockk(relaxed = true)
|
||||||
|
@ -49,25 +47,18 @@ class DeleteAndQuitTest {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
settings = Settings.getInstance(testContext).apply {
|
|
||||||
clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
every { activity.components.core.historyStorage } returns historyStorage
|
every { activity.components.core.historyStorage } returns historyStorage
|
||||||
every { activity.components.core.permissionStorage } returns permissionStorage
|
every { activity.components.core.permissionStorage } returns permissionStorage
|
||||||
every { activity.components.useCases.tabsUseCases } returns tabUseCases
|
every { activity.components.useCases.tabsUseCases } returns tabUseCases
|
||||||
every { tabUseCases.removeAllTabs } returns removeAllTabsUseCases
|
every { tabUseCases.removeAllTabs } returns removeAllTabsUseCases
|
||||||
every { activity.components.core.engine } returns engine
|
every { activity.components.core.engine } returns engine
|
||||||
}
|
every { activity.components.settings } returns settings
|
||||||
|
|
||||||
private fun Settings.clear() {
|
|
||||||
preferences.clearAndCommit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `delete only tabs and quit`() = runBlockingTest {
|
fun `delete only tabs and quit`() = runBlockingTest {
|
||||||
// When
|
// When
|
||||||
settings.setDeleteDataOnQuit(DeleteBrowsingDataOnQuitType.TABS, true)
|
every { settings.getDeleteDataOnQuit(DeleteBrowsingDataOnQuitType.TABS) } returns true
|
||||||
|
|
||||||
deleteAndQuit(activity, this, snackbar)
|
deleteAndQuit(activity, this, snackbar)
|
||||||
|
|
||||||
|
@ -97,7 +88,7 @@ class DeleteAndQuitTest {
|
||||||
fun `delete everything and quit`() = runBlockingTest {
|
fun `delete everything and quit`() = runBlockingTest {
|
||||||
// When
|
// When
|
||||||
DeleteBrowsingDataOnQuitType.values().forEach {
|
DeleteBrowsingDataOnQuitType.values().forEach {
|
||||||
settings.setDeleteDataOnQuit(it, true)
|
every { settings.getDeleteDataOnQuit(it) } returns true
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteAndQuit(activity, this, snackbar)
|
deleteAndQuit(activity, this, snackbar)
|
||||||
|
|
|
@ -6,7 +6,9 @@ package org.mozilla.fenix.trackingprotection
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import io.mockk.MockKAnnotations
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
|
import io.mockk.impl.annotations.MockK
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import io.mockk.spyk
|
import io.mockk.spyk
|
||||||
import io.mockk.verify
|
import io.mockk.verify
|
||||||
|
@ -16,28 +18,27 @@ import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.utils.Settings
|
import org.mozilla.fenix.components.metrics.MetricController
|
||||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||||
|
import org.mozilla.fenix.utils.Settings
|
||||||
|
|
||||||
@RunWith(FenixRobolectricTestRunner::class)
|
@RunWith(FenixRobolectricTestRunner::class)
|
||||||
class TrackingProtectionOverlayTest {
|
class TrackingProtectionOverlayTest {
|
||||||
|
|
||||||
private lateinit var context: Context
|
private lateinit var context: Context
|
||||||
private lateinit var settings: Settings
|
@MockK(relaxed = true) private lateinit var settings: Settings
|
||||||
private lateinit var toolbar: View
|
@MockK(relaxed = true) private lateinit var metrics: MetricController
|
||||||
private lateinit var icon: View
|
@MockK(relaxed = true) private lateinit var toolbar: View
|
||||||
private lateinit var session: Session
|
@MockK(relaxed = true) private lateinit var icon: View
|
||||||
private lateinit var overlay: TrackingProtectionOverlay
|
@MockK(relaxed = true) private lateinit var session: Session
|
||||||
|
@MockK(relaxed = true) private lateinit var overlay: TrackingProtectionOverlay
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setup() {
|
fun setup() {
|
||||||
|
MockKAnnotations.init(this)
|
||||||
context = spyk(testContext)
|
context = spyk(testContext)
|
||||||
settings = mockk(relaxed = true)
|
|
||||||
toolbar = mockk(relaxed = true)
|
|
||||||
icon = mockk(relaxed = true)
|
|
||||||
session = mockk(relaxed = true)
|
|
||||||
|
|
||||||
overlay = TrackingProtectionOverlay(context, settings) { toolbar }
|
overlay = TrackingProtectionOverlay(context, settings, metrics) { toolbar }
|
||||||
every { toolbar.findViewById<View>(R.id.mozac_browser_toolbar_tracking_protection_indicator) } returns icon
|
every { toolbar.findViewById<View>(R.id.mozac_browser_toolbar_tracking_protection_indicator) } returns icon
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.utils
|
package org.mozilla.fenix.utils
|
||||||
|
|
||||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
|
||||||
import mozilla.components.feature.sitepermissions.SitePermissionsRules
|
import mozilla.components.feature.sitepermissions.SitePermissionsRules
|
||||||
import mozilla.components.feature.sitepermissions.SitePermissionsRules.Action.ALLOWED
|
import mozilla.components.feature.sitepermissions.SitePermissionsRules.Action.ALLOWED
|
||||||
import mozilla.components.feature.sitepermissions.SitePermissionsRules.Action.ASK_TO_ALLOW
|
import mozilla.components.feature.sitepermissions.SitePermissionsRules.Action.ASK_TO_ALLOW
|
||||||
|
@ -17,8 +16,7 @@ import org.junit.Assert.assertTrue
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.mozilla.fenix.ext.clearAndCommit
|
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||||
import org.mozilla.fenix.ext.settings
|
|
||||||
import org.mozilla.fenix.settings.PhoneFeature
|
import org.mozilla.fenix.settings.PhoneFeature
|
||||||
import org.mozilla.fenix.settings.deletebrowsingdata.DeleteBrowsingDataOnQuitType
|
import org.mozilla.fenix.settings.deletebrowsingdata.DeleteBrowsingDataOnQuitType
|
||||||
|
|
||||||
|
@ -27,9 +25,18 @@ class SettingsTest {
|
||||||
|
|
||||||
lateinit var settings: Settings
|
lateinit var settings: Settings
|
||||||
|
|
||||||
|
private val defaultPermissions = SitePermissionsRules(
|
||||||
|
camera = ASK_TO_ALLOW,
|
||||||
|
location = ASK_TO_ALLOW,
|
||||||
|
microphone = ASK_TO_ALLOW,
|
||||||
|
notification = ASK_TO_ALLOW,
|
||||||
|
autoplayAudible = AutoplayAction.BLOCKED,
|
||||||
|
autoplayInaudible = AutoplayAction.BLOCKED
|
||||||
|
)
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
settings = testContext.settings().apply(Settings::clear)
|
settings = Settings(testContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -103,28 +110,6 @@ class SettingsTest {
|
||||||
assertEquals("Mozilla", settings.defaultSearchEngineName)
|
assertEquals("Mozilla", settings.defaultSearchEngineName)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun isCrashReportingEnabled_enabledInBuild() {
|
|
||||||
// When
|
|
||||||
clearExistingInstance()
|
|
||||||
val settings = testContext.settings(true)
|
|
||||||
.apply(Settings::clear)
|
|
||||||
|
|
||||||
// Then
|
|
||||||
assertTrue(settings.isCrashReportingEnabled)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun isCrashReportingEnabled_disabledInBuild() {
|
|
||||||
// When
|
|
||||||
clearExistingInstance()
|
|
||||||
val settings = testContext.settings(false)
|
|
||||||
.apply(Settings::clear)
|
|
||||||
|
|
||||||
// Then
|
|
||||||
assertFalse(settings.isCrashReportingEnabled)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun isRemoteDebuggingEnabled() {
|
fun isRemoteDebuggingEnabled() {
|
||||||
// When just created
|
// When just created
|
||||||
|
@ -451,7 +436,7 @@ class SettingsTest {
|
||||||
// When just created
|
// When just created
|
||||||
// Then
|
// Then
|
||||||
assertEquals(
|
assertEquals(
|
||||||
defaultPermissions(),
|
defaultPermissions,
|
||||||
settings.getSitePermissionsCustomSettingsRules()
|
settings.getSitePermissionsCustomSettingsRules()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -463,7 +448,7 @@ class SettingsTest {
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
assertEquals(
|
assertEquals(
|
||||||
defaultPermissions().copy(camera = BLOCKED),
|
defaultPermissions.copy(camera = BLOCKED),
|
||||||
settings.getSitePermissionsCustomSettingsRules()
|
settings.getSitePermissionsCustomSettingsRules()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -475,7 +460,7 @@ class SettingsTest {
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
assertEquals(
|
assertEquals(
|
||||||
defaultPermissions().copy(notification = BLOCKED),
|
defaultPermissions.copy(notification = BLOCKED),
|
||||||
settings.getSitePermissionsCustomSettingsRules()
|
settings.getSitePermissionsCustomSettingsRules()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -487,7 +472,7 @@ class SettingsTest {
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
assertEquals(
|
assertEquals(
|
||||||
defaultPermissions().copy(location = BLOCKED),
|
defaultPermissions.copy(location = BLOCKED),
|
||||||
settings.getSitePermissionsCustomSettingsRules()
|
settings.getSitePermissionsCustomSettingsRules()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -499,7 +484,7 @@ class SettingsTest {
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
assertEquals(
|
assertEquals(
|
||||||
defaultPermissions().copy(microphone = BLOCKED),
|
defaultPermissions.copy(microphone = BLOCKED),
|
||||||
settings.getSitePermissionsCustomSettingsRules()
|
settings.getSitePermissionsCustomSettingsRules()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -509,7 +494,7 @@ class SettingsTest {
|
||||||
settings.setSitePermissionsPhoneFeatureAction(PhoneFeature.AUTOPLAY_AUDIBLE, ALLOWED)
|
settings.setSitePermissionsPhoneFeatureAction(PhoneFeature.AUTOPLAY_AUDIBLE, ALLOWED)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
defaultPermissions().copy(autoplayAudible = ALLOWED),
|
defaultPermissions.copy(autoplayAudible = ALLOWED),
|
||||||
settings.getSitePermissionsCustomSettingsRules()
|
settings.getSitePermissionsCustomSettingsRules()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -519,25 +504,8 @@ class SettingsTest {
|
||||||
settings.setSitePermissionsPhoneFeatureAction(PhoneFeature.AUTOPLAY_INAUDIBLE, ALLOWED)
|
settings.setSitePermissionsPhoneFeatureAction(PhoneFeature.AUTOPLAY_INAUDIBLE, ALLOWED)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
defaultPermissions().copy(autoplayInaudible = ALLOWED),
|
defaultPermissions.copy(autoplayInaudible = ALLOWED),
|
||||||
settings.getSitePermissionsCustomSettingsRules()
|
settings.getSitePermissionsCustomSettingsRules()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun clearExistingInstance() {
|
|
||||||
Settings.instance = null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Settings.clear() {
|
|
||||||
preferences.clearAndCommit()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun defaultPermissions() = SitePermissionsRules(
|
|
||||||
camera = ASK_TO_ALLOW,
|
|
||||||
location = ASK_TO_ALLOW,
|
|
||||||
microphone = ASK_TO_ALLOW,
|
|
||||||
notification = ASK_TO_ALLOW,
|
|
||||||
autoplayAudible = AutoplayAction.BLOCKED,
|
|
||||||
autoplayInaudible = AutoplayAction.BLOCKED
|
|
||||||
)
|
|
||||||
|
|
|
@ -4,25 +4,24 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.whatsnew
|
package org.mozilla.fenix.whatsnew
|
||||||
|
|
||||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
import androidx.preference.PreferenceManager
|
||||||
import mozilla.components.support.test.robolectric.testContext
|
import mozilla.components.support.test.robolectric.testContext
|
||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.mozilla.fenix.ext.clearAndCommit
|
import org.mozilla.fenix.ext.clearAndCommit
|
||||||
import org.mozilla.fenix.utils.Settings
|
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||||
|
|
||||||
@RunWith(FenixRobolectricTestRunner::class)
|
@RunWith(FenixRobolectricTestRunner::class)
|
||||||
class WhatsNewStorageTest {
|
class WhatsNewStorageTest {
|
||||||
|
|
||||||
private lateinit var storage: SharedPreferenceWhatsNewStorage
|
private lateinit var storage: SharedPreferenceWhatsNewStorage
|
||||||
private lateinit var settings: Settings
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
storage = SharedPreferenceWhatsNewStorage(testContext)
|
storage = SharedPreferenceWhatsNewStorage(testContext)
|
||||||
settings = Settings.getInstance(testContext)
|
PreferenceManager.getDefaultSharedPreferences(testContext).clearAndCommit()
|
||||||
.apply(Settings::clear)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -57,7 +56,3 @@ class WhatsNewStorageTest {
|
||||||
const val DAY_IN_MILLIS = 3600 * 1000 * 24
|
const val DAY_IN_MILLIS = 3600 * 1000 * 24
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Settings.clear() {
|
|
||||||
preferences.clearAndCommit()
|
|
||||||
}
|
|
||||||
|
|
|
@ -4,24 +4,24 @@ package org.mozilla.fenix.whatsnew
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
import androidx.preference.PreferenceManager
|
||||||
import mozilla.components.support.test.robolectric.testContext
|
import mozilla.components.support.test.robolectric.testContext
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.mozilla.fenix.ext.settings
|
import org.mozilla.fenix.ext.clearAndCommit
|
||||||
import org.mozilla.fenix.utils.Settings
|
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||||
|
|
||||||
@RunWith(FenixRobolectricTestRunner::class)
|
@RunWith(FenixRobolectricTestRunner::class)
|
||||||
class WhatsNewTest {
|
class WhatsNewTest {
|
||||||
|
|
||||||
private lateinit var storage: SharedPreferenceWhatsNewStorage
|
private lateinit var storage: SharedPreferenceWhatsNewStorage
|
||||||
private lateinit var settings: Settings
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setup() {
|
fun setup() {
|
||||||
storage = SharedPreferenceWhatsNewStorage(testContext)
|
storage = SharedPreferenceWhatsNewStorage(testContext)
|
||||||
settings = testContext.settings().apply(Settings::clear)
|
PreferenceManager.getDefaultSharedPreferences(testContext).clearAndCommit()
|
||||||
WhatsNew.wasUpdatedRecently = null
|
WhatsNew.wasUpdatedRecently = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,11 +18,11 @@ def trim_to_locale(str):
|
||||||
return match.group(1)
|
return match.group(1)
|
||||||
|
|
||||||
|
|
||||||
# This file is a dumb parser that converts values from '/l10n.toml' to be easily consumed from
|
# This file is a dumb parser that converts values from '/l10n-release.toml' to be easily
|
||||||
# Python.
|
# consumed from Python.
|
||||||
#
|
#
|
||||||
# 'l10n.toml' has a very simple structure, and it is reasonable to believe that this (very basic)
|
# 'l10n-release.toml' has a very simple structure, and it is reasonable to believe that this
|
||||||
# algorithm will continue to work as it is changed.
|
# (very basic) algorithm will continue to work as it is changed.
|
||||||
#
|
#
|
||||||
# Alternatives to custom parsing that were considered:
|
# Alternatives to custom parsing that were considered:
|
||||||
# - Using standard library module --- none exists to parse TOML
|
# - Using standard library module --- none exists to parse TOML
|
||||||
|
@ -31,7 +31,7 @@ def trim_to_locale(str):
|
||||||
# - Vendoring a TOML module --- large amount of code given the use case. Introduces a security
|
# - Vendoring a TOML module --- large amount of code given the use case. Introduces a security
|
||||||
# risk
|
# risk
|
||||||
def get_release_locales():
|
def get_release_locales():
|
||||||
with open(r"l10n.toml") as f:
|
with open(r"l10n-release.toml") as f:
|
||||||
file = f.read().splitlines()
|
file = f.read().splitlines()
|
||||||
|
|
||||||
locales_opened = False
|
locales_opened = False
|
||||||
|
|
|
@ -72,7 +72,7 @@ buildscript {
|
||||||
}
|
}
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("io.gitlab.arturbosch.detekt").version("1.6.0")
|
id("io.gitlab.arturbosch.detekt").version("1.9.1")
|
||||||
}
|
}
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
|
@ -133,8 +133,7 @@ allprojects {
|
||||||
kotlinOptions.jvmTarget = "1.8"
|
kotlinOptions.jvmTarget = "1.8"
|
||||||
kotlinOptions.allWarningsAsErrors = true
|
kotlinOptions.allWarningsAsErrors = true
|
||||||
kotlinOptions.freeCompilerArgs += [
|
kotlinOptions.freeCompilerArgs += [
|
||||||
"-Xuse-experimental=kotlin.Experimental",
|
"-Xuse-experimental=kotlin.Experimental"
|
||||||
"-Xskip-runtime-version-check"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,9 +144,10 @@ task clean(type: Delete) {
|
||||||
|
|
||||||
detekt {
|
detekt {
|
||||||
// The version number is duplicated, please refer to plugins block for more details
|
// The version number is duplicated, please refer to plugins block for more details
|
||||||
version = "1.6.0"
|
version = "1.9.1"
|
||||||
input = files("$projectDir/app/src")
|
input = files("$projectDir/app/src")
|
||||||
config = files("$projectDir/config/detekt.yml")
|
config = files("$projectDir/config/detekt.yml")
|
||||||
|
baseline = file("$projectDir/config/detekt-baseline.xml")
|
||||||
|
|
||||||
reports {
|
reports {
|
||||||
html {
|
html {
|
||||||
|
|
|
@ -3,5 +3,5 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
object AndroidComponents {
|
object AndroidComponents {
|
||||||
const val VERSION = "51.0.20200720130437"
|
const val VERSION = "51.0.20200721130108"
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ object Versions {
|
||||||
const val leanplum = "5.4.0"
|
const val leanplum = "5.4.0"
|
||||||
const val osslicenses_plugin = "0.9.5"
|
const val osslicenses_plugin = "0.9.5"
|
||||||
const val osslicenses_library = "17.0.0"
|
const val osslicenses_library = "17.0.0"
|
||||||
const val detekt = "1.6.0"
|
const val detekt = "1.9.1"
|
||||||
|
|
||||||
const val androidx_appcompat = "1.2.0-rc01"
|
const val androidx_appcompat = "1.2.0-rc01"
|
||||||
const val androidx_biometric = "1.1.0-alpha01"
|
const val androidx_biometric = "1.1.0-alpha01"
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -23,10 +23,6 @@ console-reports:
|
||||||
# - 'NotificationReport'
|
# - 'NotificationReport'
|
||||||
# - 'FindingsReport'
|
# - 'FindingsReport'
|
||||||
# - 'BuildFailureReport'
|
# - 'BuildFailureReport'
|
||||||
|
|
||||||
console-reports:
|
|
||||||
active: true
|
|
||||||
exclude:
|
|
||||||
# - 'HtmlOutputReport'
|
# - 'HtmlOutputReport'
|
||||||
- 'PlainOutputReport'
|
- 'PlainOutputReport'
|
||||||
- 'XmlOutputReport'
|
- 'XmlOutputReport'
|
||||||
|
@ -34,6 +30,8 @@ console-reports:
|
||||||
comments:
|
comments:
|
||||||
active: true
|
active: true
|
||||||
excludes: "**/*Test.kt, **/*Spec.kt, **/test/**, **/androidTest/**"
|
excludes: "**/*Test.kt, **/*Spec.kt, **/test/**, **/androidTest/**"
|
||||||
|
AbsentOrWrongFileLicense:
|
||||||
|
active: true
|
||||||
CommentOverPrivateFunction:
|
CommentOverPrivateFunction:
|
||||||
active: false
|
active: false
|
||||||
CommentOverPrivateProperty:
|
CommentOverPrivateProperty:
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
/* 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/. */
|
|
@ -1,36 +0,0 @@
|
||||||
# The `activation` ping
|
|
||||||
|
|
||||||
## Description
|
|
||||||
This ping provides a measure of the activation of mobile products.
|
|
||||||
|
|
||||||
## Scheduling
|
|
||||||
The `activation` ping is automatically sent at the very first startup, after Glean is initialized.
|
|
||||||
It is only sent once and only re-attempted a subsequent startups if it hasn't been sent yet.
|
|
||||||
|
|
||||||
## Contents
|
|
||||||
This ping contains the following fields:
|
|
||||||
|
|
||||||
| Field name | Type | Description |
|
|
||||||
|---|---|---|
|
|
||||||
| `identifier` | String | An hashed and salted version of the Google Advertising ID from the device. |
|
|
||||||
| `activation_id` | UUID | An alternate identifier, not correlated with the client_id, generated once and only sent with the activation ping. |
|
|
||||||
|
|
||||||
The `activation` ping also includes the common [ping sections](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/docs/pings/pings.md#ping-sections)
|
|
||||||
found in all pings, with the exclusion of the `client_id` (as defined by the [`pings.yaml`](../app/pings.yaml) file).
|
|
||||||
|
|
||||||
## Example `activation` ping
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"ping_info": { },
|
|
||||||
"client_info": { },
|
|
||||||
"metrics": {
|
|
||||||
"string": {
|
|
||||||
"activation.identifier": "d+lnddDYN2ILBDGvhBIBHORRMrmVwTCp6rGLLFi8SMo="
|
|
||||||
},
|
|
||||||
"uuid": {
|
|
||||||
"activation.activation_id": "c0c40a5f-bd75-41ca-8097-9a38103de7fe"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
|
@ -2,21 +2,10 @@
|
||||||
|
|
||||||
Fenix uses Mozilla's telemetry service (Glean) and LeanPlum to measure feature performance and engagement.
|
Fenix uses Mozilla's telemetry service (Glean) and LeanPlum to measure feature performance and engagement.
|
||||||
|
|
||||||
## Baseline ping
|
## Glean pings and metrics
|
||||||
|
By using the Glean SDK, Fenix can send the pings the SDK owns and defines, as documented [in the Glean SDK docs](https://mozilla.github.io/glean/book/user/pings/index.html).
|
||||||
|
|
||||||
Fenix creates and tries to send a "baseline" ping when the app goes to the background. This baseline ping is defined by the [Glean](https://github.com/mozilla/glean/tree/master/docs/user/pings) component and [documented in the Android Components repository](https://github.com/mozilla/glean/blob/master/docs/user/pings/baseline.md).
|
Additional metrics or pings defined by Fenix are documented in the [Glean SDK autogenerated docs](metrics.md).
|
||||||
|
|
||||||
## Metrics ping
|
|
||||||
|
|
||||||
Fenix creates and tries to send a "baseline" ping. It is defined inside the [`metrics.yaml`](https://github.com/mozilla-mobile/fenix/blob/master/app/metrics.yaml) file. This ping includes things like whether or not Fenix is currently the default browser.
|
|
||||||
|
|
||||||
## Events
|
|
||||||
|
|
||||||
Fenix sends event pings that allows us to measure feature performance. These are defined inside the [`metrics.yaml`](https://github.com/mozilla-mobile/fenix/blob/master/app/metrics.yaml) file.
|
|
||||||
|
|
||||||
## Activation
|
|
||||||
|
|
||||||
Fenix sends an activation ping once, at startup. Further documentation can be found in the [`activation` ping](activation.md) docs.
|
|
||||||
|
|
||||||
## Leanplum
|
## Leanplum
|
||||||
See [here](https://github.com/mozilla-mobile/fenix/blob/master/docs/mma.md) for details on Leanplum usage in Firefox Preview.
|
See [here](https://github.com/mozilla-mobile/fenix/blob/master/docs/mma.md) for details on Leanplum usage in Firefox Preview.
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
# Locales that should be present in release builds
|
||||||
|
# Locales that are at 70% or higher completion on https://pontoon.mozilla.org/projects/android-l10n/
|
||||||
|
# should be in this list
|
||||||
|
locales = [
|
||||||
|
"an",
|
||||||
|
"ar",
|
||||||
|
"ast",
|
||||||
|
"az",
|
||||||
|
"be",
|
||||||
|
"bn",
|
||||||
|
"br",
|
||||||
|
"bs",
|
||||||
|
"ca",
|
||||||
|
"cak",
|
||||||
|
"co",
|
||||||
|
"cs",
|
||||||
|
"cy",
|
||||||
|
"da",
|
||||||
|
"de",
|
||||||
|
"dsb",
|
||||||
|
"el",
|
||||||
|
"en-CA",
|
||||||
|
"en-GB",
|
||||||
|
"eo",
|
||||||
|
"es",
|
||||||
|
"es-AR",
|
||||||
|
"es-CL",
|
||||||
|
"es-ES",
|
||||||
|
"es-MX",
|
||||||
|
"et",
|
||||||
|
"eu",
|
||||||
|
"fa",
|
||||||
|
"ff",
|
||||||
|
"fi",
|
||||||
|
"fr",
|
||||||
|
"fy-NL",
|
||||||
|
"ga-IE",
|
||||||
|
"gd",
|
||||||
|
"gn",
|
||||||
|
"gu-IN",
|
||||||
|
"he",
|
||||||
|
"hi-IN",
|
||||||
|
"hr",
|
||||||
|
"hsb",
|
||||||
|
"hu",
|
||||||
|
"hy-AM",
|
||||||
|
"id",
|
||||||
|
"is",
|
||||||
|
"it",
|
||||||
|
"ja",
|
||||||
|
"ka",
|
||||||
|
"kab",
|
||||||
|
"kk",
|
||||||
|
"kn",
|
||||||
|
"ko",
|
||||||
|
"lij",
|
||||||
|
"lo",
|
||||||
|
"lt",
|
||||||
|
"ml",
|
||||||
|
"mr",
|
||||||
|
"my",
|
||||||
|
"nb-NO",
|
||||||
|
"nl",
|
||||||
|
"nn-NO",
|
||||||
|
"oc",
|
||||||
|
"pa-IN",
|
||||||
|
"pl",
|
||||||
|
"pt-BR",
|
||||||
|
"pt-PT",
|
||||||
|
"rm",
|
||||||
|
"ro",
|
||||||
|
"ru",
|
||||||
|
"sk",
|
||||||
|
"sl",
|
||||||
|
"sq",
|
||||||
|
"sr",
|
||||||
|
"su",
|
||||||
|
"sv-SE",
|
||||||
|
"ta",
|
||||||
|
"te",
|
||||||
|
"th",
|
||||||
|
"tr",
|
||||||
|
"trs",
|
||||||
|
"uk",
|
||||||
|
"ur",
|
||||||
|
"vec",
|
||||||
|
"vi",
|
||||||
|
"zh-CN",
|
||||||
|
"zh-TW",
|
||||||
|
]
|
||||||
|
|
|
@ -7,6 +7,7 @@ locales = [
|
||||||
"ast",
|
"ast",
|
||||||
"az",
|
"az",
|
||||||
"be",
|
"be",
|
||||||
|
"bg",
|
||||||
"bn",
|
"bn",
|
||||||
"br",
|
"br",
|
||||||
"bs",
|
"bs",
|
||||||
|
@ -58,10 +59,13 @@ locales = [
|
||||||
"lt",
|
"lt",
|
||||||
"ml",
|
"ml",
|
||||||
"mr",
|
"mr",
|
||||||
|
"ms",
|
||||||
"my",
|
"my",
|
||||||
"nb-NO",
|
"nb-NO",
|
||||||
|
"ne-NP",
|
||||||
"nl",
|
"nl",
|
||||||
"nn-NO",
|
"nn-NO",
|
||||||
|
"nv",
|
||||||
"oc",
|
"oc",
|
||||||
"pa-IN",
|
"pa-IN",
|
||||||
"pl",
|
"pl",
|
||||||
|
@ -83,6 +87,7 @@ locales = [
|
||||||
"trs",
|
"trs",
|
||||||
"uk",
|
"uk",
|
||||||
"ur",
|
"ur",
|
||||||
|
"uz",
|
||||||
"vec",
|
"vec",
|
||||||
"vi",
|
"vi",
|
||||||
"zh-CN",
|
"zh-CN",
|
||||||
|
|
|
@ -45,22 +45,14 @@ if (localProperties != null) {
|
||||||
|
|
||||||
if (appServicesLocalPath != null) {
|
if (appServicesLocalPath != null) {
|
||||||
log("Enabling automatic publication of application-services from: $appServicesLocalPath")
|
log("Enabling automatic publication of application-services from: $appServicesLocalPath")
|
||||||
def publishAppServicesCmd = ["./automation/publish_to_maven_local_if_modified.py"]
|
// Windows can't execute .py files directly, so we assume a "manually installed" python,
|
||||||
// Application-services doesn't build on native Windows. However, it still makes sense to
|
// which comes with a "py" launcher and respects the shebang line to specify the version.
|
||||||
// enable these workflows on Windows, even if it isn't quote as automatic as elsewhere -
|
def publishAppServicesCmd = [];
|
||||||
// specifically, you must run the build command on WSL, but after that you can happily build
|
|
||||||
// and debug directly from within Android Studio on native Windows - but only after following
|
|
||||||
// https://github.com/mozilla/application-services/blob/master/docs/howtos/setup-android-build-environment.md#using-windows
|
|
||||||
// So rather than fail we make noise...
|
|
||||||
if (System.properties['os.name'].toLowerCase().contains('windows')) {
|
if (System.properties['os.name'].toLowerCase().contains('windows')) {
|
||||||
log('NOTE: The autoPublish workflows do not work on native windows.');
|
publishAppServicesCmd << "py";
|
||||||
log('You must manually ensure that the following command has completed successfully in WSL:');
|
|
||||||
log("> $publishAppServicesCmd");
|
|
||||||
log("(from the '$appServicesLocalPath' directory)");
|
|
||||||
log('Then restart the build');
|
|
||||||
} else {
|
|
||||||
runCmd(publishAppServicesCmd, appServicesLocalPath, "Published application-services for local development.", false)
|
|
||||||
}
|
}
|
||||||
|
publishAppServicesCmd << "./automation/publish_to_maven_local_if_modified.py";
|
||||||
|
runCmd(publishAppServicesCmd, appServicesLocalPath, "Published application-services for local development.", false)
|
||||||
} else {
|
} else {
|
||||||
log("Disabled auto-publication of application-services. Enable it by settings '$settingAppServicesPath' in local.properties")
|
log("Disabled auto-publication of application-services. Enable it by settings '$settingAppServicesPath' in local.properties")
|
||||||
}
|
}
|
||||||
|
@ -68,10 +60,8 @@ if (localProperties != null) {
|
||||||
String androidComponentsLocalPath = localProperties.getProperty(settingAndroidComponentsPath)
|
String androidComponentsLocalPath = localProperties.getProperty(settingAndroidComponentsPath)
|
||||||
|
|
||||||
if (androidComponentsLocalPath != null) {
|
if (androidComponentsLocalPath != null) {
|
||||||
// android-components does build on native windows, so it doesn't get the special Windows treatment above.
|
|
||||||
// But it doesn't like executing .py files directly. We assume a "manually installed" python,
|
|
||||||
// which comes with a "py" launcher and respects the shebang line to specify the version.
|
|
||||||
log("Enabling automatic publication of android-components from: $androidComponentsLocalPath")
|
log("Enabling automatic publication of android-components from: $androidComponentsLocalPath")
|
||||||
|
// As above, hacks to execute .py files on Windows.
|
||||||
def publishAcCmd = [];
|
def publishAcCmd = [];
|
||||||
if (System.properties['os.name'].toLowerCase().contains('windows')) {
|
if (System.properties['os.name'].toLowerCase().contains('windows')) {
|
||||||
publishAcCmd << "py";
|
publishAcCmd << "py";
|
||||||
|
|
|
@ -82,7 +82,7 @@ job-defaults:
|
||||||
- '--app=fenix'
|
- '--app=fenix'
|
||||||
- '--browsertime'
|
- '--browsertime'
|
||||||
- '--cold'
|
- '--cold'
|
||||||
- '--binary=org.mozilla.fenix.nightly'
|
- '--binary=org.mozilla.fenix'
|
||||||
- '--activity=org.mozilla.fenix.IntentReceiverActivity'
|
- '--activity=org.mozilla.fenix.IntentReceiverActivity'
|
||||||
- '--download-symbols=ondemand'
|
- '--download-symbols=ondemand'
|
||||||
- '--browsertime-node=$MOZ_FETCHES_DIR/node/bin/node'
|
- '--browsertime-node=$MOZ_FETCHES_DIR/node/bin/node'
|
||||||
|
@ -232,3 +232,15 @@ jobs:
|
||||||
test-name: google-search-restaurants
|
test-name: google-search-restaurants
|
||||||
treeherder:
|
treeherder:
|
||||||
symbol: 'Btime(tp6m-28-c)'
|
symbol: 'Btime(tp6m-28-c)'
|
||||||
|
|
||||||
|
youtube-playback:
|
||||||
|
test-name: youtube-playback
|
||||||
|
run-visual-metrics: False
|
||||||
|
treeherder:
|
||||||
|
symbol: 'Btime(ytp)'
|
||||||
|
args:
|
||||||
|
by-abi:
|
||||||
|
# Bug 1558456 - Stop tracking youtube-playback-test on motoG5 for >1080p cases
|
||||||
|
armeabi-v7a:
|
||||||
|
- '--test-url-params=exclude=1,2,9,10,17,18,21,22,26,28,30,32,39,40,47,48,55,56,63,64,71,72,79,80,83,84,89,90,95,96'
|
||||||
|
default: []
|
||||||
|
|
|
@ -93,17 +93,6 @@ jobs:
|
||||||
treeherder:
|
treeherder:
|
||||||
symbol: forPerformanceTest(B)
|
symbol: forPerformanceTest(B)
|
||||||
|
|
||||||
nightly:
|
|
||||||
attributes:
|
|
||||||
nightly: true
|
|
||||||
include-nightly-version: true
|
|
||||||
include-shippable-secrets: true
|
|
||||||
run:
|
|
||||||
geckoview-engine: geckoNightly
|
|
||||||
gradle-build-type: fenixNightly
|
|
||||||
treeherder:
|
|
||||||
symbol: nightly(B)
|
|
||||||
|
|
||||||
nightly-simulation:
|
nightly-simulation:
|
||||||
attributes:
|
attributes:
|
||||||
nightly: false
|
nightly: false
|
||||||
|
@ -112,47 +101,22 @@ jobs:
|
||||||
include-shippable-secrets: true
|
include-shippable-secrets: true
|
||||||
run:
|
run:
|
||||||
geckoview-engine: geckoNightly
|
geckoview-engine: geckoNightly
|
||||||
gradle-build-type: fennecNightly
|
gradle-build-type: fenixProduction
|
||||||
treeherder:
|
treeherder:
|
||||||
symbol: nightlySim(B)
|
symbol: nightlySim(B)
|
||||||
|
|
||||||
beta:
|
nightly:
|
||||||
attributes:
|
|
||||||
release-type: beta
|
|
||||||
include-release-version: true
|
|
||||||
include-shippable-secrets: true
|
|
||||||
filter-incomplete-translations: true
|
|
||||||
run:
|
|
||||||
geckoview-engine: geckoBeta
|
|
||||||
gradle-build-type: fenixBeta
|
|
||||||
run-on-tasks-for: [github-release]
|
|
||||||
treeherder:
|
|
||||||
symbol: beta(B)
|
|
||||||
|
|
||||||
# XXX `production` is now the new nightly. We keep this name around while we officially remove
|
|
||||||
# `nightly` and `fennec-nightly`
|
|
||||||
production:
|
|
||||||
attributes:
|
attributes:
|
||||||
nightly: true
|
nightly: true
|
||||||
include-nightly-version: true
|
include-nightly-version: true
|
||||||
include-shippable-secrets: true
|
include-shippable-secrets: true
|
||||||
run:
|
run:
|
||||||
geckoview-engine: geckoNightly
|
geckoview-engine: geckoNightly
|
||||||
|
# XXX `fenixProduction` is now the new nightly.
|
||||||
gradle-build-type: fenixProduction
|
gradle-build-type: fenixProduction
|
||||||
run-on-tasks-for: [github-release]
|
run-on-tasks-for: []
|
||||||
treeherder:
|
treeherder:
|
||||||
symbol: production(B)
|
symbol: nightly(B)
|
||||||
|
|
||||||
fennec-nightly:
|
|
||||||
attributes:
|
|
||||||
nightly: true
|
|
||||||
include-nightly-version: true
|
|
||||||
include-shippable-secrets: true
|
|
||||||
run:
|
|
||||||
geckoview-engine: geckoNightly
|
|
||||||
gradle-build-type: fennecNightly
|
|
||||||
treeherder:
|
|
||||||
symbol: nightlyFennec(B)
|
|
||||||
|
|
||||||
fennec-beta:
|
fennec-beta:
|
||||||
attributes:
|
attributes:
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
trust-domain: mobile
|
trust-domain: mobile
|
||||||
treeherder:
|
treeherder:
|
||||||
group-names:
|
group-names:
|
||||||
'beta': 'Beta-related tasks'
|
|
||||||
'betaFennec': 'Beta-related tasks with same APK configuration as Fennec'
|
'betaFennec': 'Beta-related tasks with same APK configuration as Fennec'
|
||||||
'Btime': 'Raptor-Browsertime tests'
|
'Btime': 'Raptor-Browsertime tests'
|
||||||
'bump': 'Bump dependencies'
|
'bump': 'Bump dependencies'
|
||||||
|
@ -12,7 +11,6 @@ treeherder:
|
||||||
'I': 'Docker Image Builds'
|
'I': 'Docker Image Builds'
|
||||||
'nightly': 'Nightly-related tasks'
|
'nightly': 'Nightly-related tasks'
|
||||||
'nightlySim': 'Nightly-related tasks that run on each github push'
|
'nightlySim': 'Nightly-related tasks that run on each github push'
|
||||||
'nightlyFennec': 'Nightly-related tasks with same APK configuration as Fennec'
|
|
||||||
'production': 'Release-related tasks'
|
'production': 'Release-related tasks'
|
||||||
'productionFennec': 'Production-related tasks with same APK configuration as Fennec'
|
'productionFennec': 'Production-related tasks with same APK configuration as Fennec'
|
||||||
'Rap': 'Raptor tests'
|
'Rap': 'Raptor tests'
|
||||||
|
|
|
@ -17,8 +17,8 @@ primary-dependency: push-apk
|
||||||
group-by: build-type
|
group-by: build-type
|
||||||
|
|
||||||
only-for-build-types:
|
only-for-build-types:
|
||||||
- fenix-beta
|
- fennec-beta
|
||||||
- fenix-production
|
- fennec-production
|
||||||
|
|
||||||
job-template:
|
job-template:
|
||||||
description: Mark Fenix as shipped in ship-it
|
description: Mark Fenix as shipped in ship-it
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue