diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d5c297efb..b11a4c32f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -42,14 +42,17 @@ # Therefore, we make the Perfomance team code owners of this file. /.github/CODEOWNERS @mozilla-mobile/Performance -/app/src/*/java/org/mozilla/fenix/perf/** @mozilla-mobile/Performance +# Own /perf/ src directories which typically includes perf code architecture +# or code that monitors for perf regressions. This is our main way to own code +# because it's simpler and less fragile than listing many specific files to own. +/**/src/**/perf/** @mozilla-mobile/Performance + +# Possible regressions throughout the app *.pro @mozilla-mobile/Performance *proguard* @mozilla-mobile/Performance # Possible startup regressions *Application.kt @mozilla-mobile/Performance -*StrictMode*kt @mozilla-mobile/Performance -*ConstraintLayoutPerfDetector.kt @mozilla-mobile/Performance # We want to be aware of new features behind flags as well as features # about to be enabled. diff --git a/.github/ISSUE_TEMPLATE/release_checklist.md b/.github/ISSUE_TEMPLATE/release_checklist.md index c6e3425a5..9f9e08b6e 100644 --- a/.github/ISSUE_TEMPLATE/release_checklist.md +++ b/.github/ISSUE_TEMPLATE/release_checklist.md @@ -1,67 +1,76 @@ ## Overview ## -| Monday | Tuesday | Wednesday | Thursday | Friday | -|-----------------|---------------------------|------------------------------|----------------|-------------| -| (Sprint 1 Start)| | | | | -| | Hard code freeze for Beta | | | Code Freeze/Planning -| Sprint 2 Start / Release to Beta / Release Production in Play Store 1% | QA Beta / Promote Release 25% | Promote Release 100% | | | +Firefox for Android roughly follows the [Firefox Gecko release schedule](https://wiki.mozilla.org/Release_Management/Calendar#Calendars). +This means we cut a beta at the end of every two sprints, with a full cycle (~4 weeks) of baking on Beta before going to release. Uplifts must be approved by Release Owner (st3fan). + +The [Firefox for Android release schedule](https://docs.google.com/spreadsheets/d/1HotjliSCGOp2nTkfXrxv8qYcurNpkqLWBKbbId6ovTY/edit#gid=0) contains more details related to specific Mobile handoffs. + +| Monday | Tuesday | Wednesday | Thursday | Friday | +|-----------------|---------------------------|--------------------------------|-------------------|-----------------| +| (week 1) | | (Y.2 sprint ended) |Sprint **X.1** starts | | +| (week 2) | | | | | +| (week 3) | | Cut **X.1-beta** 12PST | **X.1-beta** QA / Sprint X.2 starts || +| (week 4) | | | | | +| (week 5) | | Uplift L10N to **X.1-beta** | Sprint Z.1 starts | | +| (week 6) | Build X.1-RC with GV Prod for QA | | | | +| (week 7) | Release X.1 - 5% | Release X.1 20% / Cut Z.1-beta | Release X.1 100% | | ### Requirements -- Jira account +- JIRA access - Bugzilla account -- Google Play access (for reviewing crashes) +- Sentry access ## Release Checklist -There are two releases this covers: the current sprint that is going out to Beta, and the previous beta that is going to Production. -We will refer to the beta release going out as the *current* sprint release. +There are two releases this covers: the current sprint that is going out to Beta, and the previous Beta that is going to Production. -## Start of sprint [Monday, 1st week of sprint] -- [ ] Create milestone for *upcoming* sprint release. (e.g. if you are doing releng for v2.2, create v2.3 milestone) -- [ ] If the upcoming release is a *major* (x.0) release, create an issue in the *upcoming* milestone: "What's New Entry for [*upcoming* release]" to track work for the SUMO page and Google Play release notes, e.g., if the current release is 2.3 but the upcoming one will be 3.0, make a "What's New" issue for 3.0. Product will use this to remember to check in with SUMO. -- [ ] [Create an issue](https://github.com/mozilla-mobile/fenix/issues/new?template=release_checklist.md&title=Releng+for+) in the *upcoming* milestone: "Releng for v[release]". Find an engineer who will handle the next releng task and assign them. +## Start of Sprint X.1 [Thursday, 1st week of sprint] +- [ ] [Create an issue](https://github.com/mozilla-mobile/fenix/issues/new?template=release_checklist.md&title=Releng+for+) "Releng for v[release]" to track the current sprint. -## Release Day [Monday, 3rd week] Beta & Production -- [ ] Promote previous Beta to Release - - [ ] Cherry-pick all merged [automated L10N string PRs](https://github.com/mozilla-mobile/fenix/pull/6156) to add newly translated strings and open a PR against branch that is going to release. (TODO is this safe?) This will require review. - - [ ] Tag the latest released RC version additionally with the tag of the release (v1.0-RC2 -> v1.0) (This can be done as soon as there are no more release blockers, does not need to be on Release Day.) - - [ ] **Verify that the commit hash of the new release matches the most recent RC.** This ensures that the correct version will be released - - [ ] Create a GitHub release build `vX.X.X` (v2.3.0) with the previous Beta branch as the target. - - [ ] Smoketest the signed build - - [ ] Load a url - - [ ] Set up sync - - [ ] Delete browsing data - - [ ] Upload the signed APK from the Taskcluster `signing-production` task to the [release page](https://github.com/mozilla-mobile/fenix/releases) - - [ ] Create a release request in Bugzilla to release to 1%. You can clone [this issue](https://bugzilla.mozilla.org/show_bug.cgi?id=1571967) and `need-info` someone from release management. +## Sprint X.1 End [Wednesday, 2nd week] Cutting a Beta - [ ] Make a new Beta - - [ ] Create a branch off of master (DO NOT PUSH YET) for the *current* milestone of format `releases/v2.3` (where 2.3 is the *current* milestone). After that, anything landing in master will be part of the next milestone. - - [ ] On the new Beta branch, pin the AC version to the stable version ([example](https://github.com/mozilla-mobile/fenix/commit/e413da29f6a7a7d4a765817a9cd5687abbf27619)) with commit message "Issue #``: Pin to stable AC `` for release v2.3" (replacing 2.3 with the version) - - For each issue closed since the last release (run `kotlinc -script automation/releasetools/PrintMentionedIssuesAndPrs.kts` to get a list [see script for details] and paste it into the Releng issue): - - [ ] Ensure it has the correct milestone. - - [ ] Add `eng:qa:needed` flags on each issue that still needs it. - - [ ] Go through the list of issues closed during this sprint in the Done column of the [Sprint Kanban](https://github.com/mozilla-mobile/fenix/projects/9) and make sure they all have the correct milestone. + - [ ] Create a branch off of master (DO NOT PUSH YET) for the *current* milestone of format `releases/v85.0.0`. After that, anything landing in master will be part of the next release. + - [ ] On the new Beta branch, pin the AC version to the stable version ([example](https://github.com/mozilla-mobile/fenix/commit/e413da29f6a7a7d4a765817a9cd5687abbf27619)) with commit message "Issue #``: Pin to stable AC `` for release v85" + - [ ] Update the title to include this AC version "Releng for v[release] with AC [version]" - Note: You will need code review to make changes to the release branch after this point, because it is a protected branch. - [ ] Push the branch. - - [ ] Create a GitHub pre-release build `vX.X.X-beta.1` (v2.3.0-beta.1) with the release branch as the target. This will kick off a build of the branch. You can see it in the mouseover of the CI badge of the branch in the commits view. Builds are found under `signing-*` task. - - If you need to trigger a new RC build, you will need to draft and publish a new (pre-release) release. Editing an existing release and creating a new tag will not trigger a new RC build. - - - [ ] Create a new PI (product integrity) request in Jira. You can clone [this issue](https://jira.mozilla.com/browse/PI-219). - -### SUMO Verification [After Beta release] -- [ ] If the *current* release is a major (x.0) release, review the SUMO article contents of the whats new / other sumo pages and make sure they are accurate with what is in this release. If not, escalate to Product Owner. + - [ ] Create a GitHub pre-release [Release](https://github.com/mozilla-mobile/fenix/releases) with: + - [ ] Tag of the format `vX.X.X-beta.1` (v85.0.0-beta.1) + - [ ] The Target branch is the release branch (releases/v85.0.0) + - [ ] For the description of the release, look at the [Jira boards](https://jira.mozilla.com/secure/RapidBoard.jspa?rapidView=299&projectKey=FNX&view=reporting&chart=sprintRetrospective&sprint=883) for the X.1 and previous Y.2 sprints and list the major features that were added. This will help with the release notes later on. + - [ ] Click "Publish release". This will kick off a build of the branch. You can see it in the mouseover of the CI badge of the branch in the commits view. Builds are found under `signing-*` task. + - If you need to trigger a new RC build, you **MUST** draft and publish a new (pre-release) release (optionally deleting both the release and the tag). Editing an existing release and creating a new tag will **not** trigger a new build. + - [ ] Send an email to QA at mozilla-mobile-qa@softvision.com with a link to the Taskcluster build (subdirectory of the [Fenix CI](https://firefox-ci-tc.services.mozilla.com/tasks/index/mobile.v2.fenix.beta)) -### During Beta Product Integrity (Beta Release until PI green signoff) +### Bugfix uplifts / Beta Product Integrity (Beta Release until PI green signoff) - [ ] If bugs are considered release blocker then find someone to fix them on master and the milestone branch (cherry-pick / uplift) -- [ ] If needed tag a new RC version (e.g. v1.0-RC2) and follow the submission checklist again. + - [ ] Add the uplift request to the appropriate row in the [Uplifts document](https://docs.google.com/spreadsheets/d/1qIvHpcQ3BqJtlzV5T4M1MhbWVxkNiG-ToeYnWEBW4-I/edit#gid=0). +- [ ] If needed tag a new beta version (e.g. v1.0-beta.2) and follow the submission checklist again. +- [ ] Once there is GREEN QA signoff, file a [release management bugzilla for rollout](https://bugzilla.mozilla.org/show_bug.cgi?id=1664366) + - [ ] Check Sentry each day for issues on [Firefox Beta](https://sentry.prod.mozaws.net/operations/firefox-beta/) and if nothing concerning, bump release in the bugzilla (5%, 20%, 100%) -### During Production Release Rollout [Tuesday, Wednesday following Monday Release Day] -- [ ] Check Sentry for new crashes. File issues and triage. -- [ ] Ask Relman in the bug if they see potential blockers on Google Play, and if not, request that they bump the release each day (25% Tu, 100% Wed) +### Uplifting L10N strings to Beta [Wednesday, 2 weeks after sprint end] +- [ ] Find the issue ([example](https://github.com/mozilla-mobile/fenix/issues/16381)) filed by L10N / delphine saying string are ready for uplift (it takes 2 weeks for localizers to prepare localization). +- [ ] If there are new locales that are ready to be added to Release, add them to [l10n-release.toml](https://github.com/mozilla-mobile/fenix/blob/master/l10n-release.toml) +- [ ] Run the [L10N uplift script](https://github.com/mozilla-mobile/fenix/blob/master/l10n-uplift.py) against the releases/vX.1 branch (releases/v85.0.0). There will likely be conflicts, but if you are confused, they should match the strings in [main/Nightly](https://github.com/mozilla-mobile/fenix/tree/master/app/src/main/res) +- [ ] Once all conflicts are resolved, tag a new Beta to be released. +- [ ] Notify delphine in the L10N issue that the strings have been uplifted, and string quarantine can be lifted + +### Production Release Candidate [Tuesday, 3 weeks after X.1 Beta was cut] +- [ ] In android-components: Create a dot release with the GeckoView Production release candidate. +- [ ] Open a PR against the release branch (releases/v85.0.0) with the AC version bump "Pin to stable AC `` for release v85`. You will need code review. +- [ ] Create a GitHub pre-release [Release](https://github.com/mozilla-mobile/fenix/releases) with: + - [ ] Tag of the format `vX.X.X-rc.1` (v85.0.0-rc.1) + - [ ] The Target branch is the release branch (releases/v85.0.0) + - [ ] For the description, copy the beta description +- [ ] Send an email to QA at mozilla-mobile-qa@softvision.com with a link to the Taskcluster build (subdirectory of the [Fenix CI](https://firefox-ci-tc.services.mozilla.com/tasks/index/mobile.v2.fenix.release)) - Major releases often need to be synchronized with other marketing activities (e.g. blog postings). +### Production Release [Release day, from [release calendar](https://docs.google.com/spreadsheets/d/1HotjliSCGOp2nTkfXrxv8qYcurNpkqLWBKbbId6ovTY/edit#gid=0)] +- [ ] Create a GitHub [Release](https://github.com/mozilla-mobile/fenix/releases) with: + - [ ] Tag of the format `vX.1.X` (v85.1.0) (increment the minor version for new cuts) + - [ ] The Target branch is the release branch (releases/v85.0.0) + - [ ] For the description, copy the beta description + - [ ] file Bugzilla ticket for [release manament](https://bugzilla.mozilla.org/show_bug.cgi?id=1672212) -## Room for improvement -- [ ] Automate assigning milestones to closed issues (based on date, etc) #6199 -- [ ] Automate assignig `eng:qa:needed` to issues #6199 -- [ ] Automate verification that the commit hash matches the most recent RC -- [ ] Builds generated as part of `signing-production` task look like `public/build/arm64-v8a/geckoBeta/target.apk`. This means that the dev must download, then rename them by hand. Could RM update these to generate `public/build/arm64-v8a/geckoBeta/firefox-preview-v3.0.0-rc.1-arm64-v8a.apk`, or similar? +- [ ] Check Sentry for new crashes. File issues and triage. +- [ ] Each day, bump the release rollout if nothing concerning (5%, 20%, 100%) diff --git a/.github/workflows/update-ac.yml b/.github/workflows/update-ac.yml new file mode 100644 index 000000000..952b16c30 --- /dev/null +++ b/.github/workflows/update-ac.yml @@ -0,0 +1,23 @@ +# 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/ + +name: "Update Android-Components" + +on: + schedule: + - cron: '*/15 * * * *' + +jobs: + main: + name: "Update Android-Components" + runs-on: ubuntu-20.04 + steps: + - name: "Update Android-Components" + uses: mozilla-mobile/relbot@master + if: github.repository == 'mozilla-mobile/fenix' + with: + project: fenix + command: update-android-components + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.taskcluster.yml b/.taskcluster.yml index aaf457d5e..3441951e6 100644 --- a/.taskcluster.yml +++ b/.taskcluster.yml @@ -8,7 +8,7 @@ tasks: - $let: taskgraph: branch: taskgraph - revision: 12992b0f984884ec2b0a7bdedc3b3ba467363eb4 + revision: 2b2622598df02bde211d8cedb334b7b22fb883a4 trustDomain: mobile in: $let: @@ -104,7 +104,7 @@ tasks: tasks_for in ["action", "cron"] || (tasks_for == "github-pull-request" && pullRequestAction in ["opened", "reopened", "synchronize"]) || (tasks_for == "github-push" && head_branch[:10] != "refs/tags/") && (head_branch != "staging.tmp") && (head_branch != "trying.tmp") - || (tasks_for == "github-release" && releaseAction == "published") + || (tasks_for == "github-release" && releaseAction == "published" && (ownerEmail != "mozilla-release-automation-bot@users.noreply.github.com") && (ownerEmail != "mozilla-release-automation-bot-staging@users.noreply.github.com")) then: $let: level: @@ -243,7 +243,7 @@ tasks: # Note: This task is built server side without the context or tooling that # exist in tree so we must hard code the hash image: - mozillareleases/taskgraph:decision-mobile-6607973bc60e32323a541861cc5856cd6a0f51ea9fd664ef7d43bca8df53db47@sha256:8c471aacc469ea8e7bb4846c16efe086f7350a5cc1df570cc6c86b22895a2456 + mozillareleases/taskgraph:decision-mobile-682fbaa1ef17e70ddfe3457da3eaf8e776c4a20fe5bfbdbeba0641fd5bceae2a@sha256:bbb2613aaab79d17e590fbd78c072d0643be40fd1237195703f84280ecc3b302 maxRunTime: 1800 @@ -261,12 +261,13 @@ tasks: $if: 'tasks_for == "action"' then: > PIP_IGNORE_INSTALLED=0 pip install --user /builds/worker/checkouts/taskgraph && + PIP_IGNORE_INSTALLED=0 pip install --user mozilla-version && taskcluster/scripts/decision-install-sdk.sh && ln -s /builds/worker/artifacts artifacts && ~/.local/bin/taskgraph action-callback else: > PIP_IGNORE_INSTALLED=0 pip install --user /builds/worker/checkouts/taskgraph && - PIP_IGNORE_INSTALLED=0 pip install --user arrow taskcluster pyyaml && + PIP_IGNORE_INSTALLED=0 pip install --user mozilla-version && taskcluster/scripts/decision-install-sdk.sh && ln -s /builds/worker/artifacts artifacts && ~/.local/bin/taskgraph decision diff --git a/app/build.gradle b/app/build.gradle index 559941735..8030c5d0e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -37,6 +37,13 @@ android { manifestPlaceholders = [ "deepLinkScheme": deepLinkSchemeValue ] + + // Build flag for "Mozilla Online" variants. See `Config.isMozillaOnline`. + if (project.hasProperty("mozillaOnline") || gradle.hasProperty("localProperties.mozillaOnline")) { + buildConfigField "boolean", "MOZILLA_ONLINE", "true" + } else { + buildConfigField "boolean", "MOZILLA_ONLINE", "false" + } } def releaseTemplate = { @@ -206,6 +213,17 @@ android { testOptions { unitTests.returnDefaultValues = true + + unitTests.all { + // We keep running into memory issues when running our tests. With this config we + // reserve more memory and also create a new process after every 80 test classes. This + // is a band-aid solution and eventually we should try to find and fix the leaks + // instead. :) + maxParallelForks = 2 + forkEvery = 80 + maxHeapSize = "2048m" + minHeapSize = "1024m" + } } } diff --git a/app/metrics.yaml b/app/metrics.yaml index fd6de67c9..8bdbdc044 100644 --- a/app/metrics.yaml +++ b/app/metrics.yaml @@ -433,21 +433,6 @@ onboarding: - fenix-core@mozilla.com - erichards@mozilla.com expires: "2021-08-01" - whats_new: - type: event - description: - The onboarding What\'s New card was tapped. - bugs: - - https://github.com/mozilla-mobile/fenix/issues/10824 - data_reviews: - - https://github.com/mozilla-mobile/fenix/pull/11867 - - https://github.com/mozilla-mobile/fenix/pull/15713#issuecomment-703972068 - data_sensitivity: - - interaction - notification_emails: - - fenix-core@mozilla.com - - erichards@mozilla.com - expires: "2021-08-01" pref_toggled_theme_picker: type: event description: @@ -569,13 +554,15 @@ context_menu: ``` open_in_new_tab, open_in_private_tab, open_image_in_new_tab, - save_image, share_link, copy_link, copy_image_location + save_image, share_link, copy_link, copy_image_location, share_image ``` bugs: - https://github.com/mozilla-mobile/fenix/issues/957 + - https://github.com/mozilla-mobile/fenix/issues/16076 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/1344#issuecomment-479285010 - https://github.com/mozilla-mobile/fenix/pull/13958#issuecomment-676857877 + - https://github.com/mozilla-mobile/fenix/issues/16076#issuecomment-726216734 data_sensitivity: - interaction notification_emails: @@ -698,6 +685,23 @@ metrics: notification_emails: - fenix-core@mozilla.com expires: "2021-08-01" + distribution_id: + type: string + lifetime: application + description: | + A string containing the distribution identifier. This is currently used + to identify installs from Mozilla Online. + send_in_pings: + - metrics + bugs: + - https://github.com/mozilla-mobile/fenix/issues/16075 + data_reviews: + - https://github.com/mozilla-mobile/fenix/issues/16075 + data_sensitivity: + - technical + notification_emails: + - fenix-core@mozilla.com + expires: never top_sites_count: type: counter lifetime: application @@ -1659,67 +1663,6 @@ activation: no_lint: - USER_LIFETIME_EXPIRATION -qr_scanner: - opened: - type: event - description: | - A user opened the QR scanner - bugs: - - https://github.com/mozilla-mobile/fenix/issues/1857 - data_reviews: - - https://github.com/mozilla-mobile/fenix/pull/2524#issuecomment-492739967 - - https://github.com/mozilla-mobile/fenix/pull/15713#issuecomment-703972068 - data_sensitivity: - - interaction - notification_emails: - - fenix-core@mozilla.com - expires: "2021-08-01" - prompt_displayed: - type: event - description: | - A user scanned a QR code, causing a confirmation prompt to display asking - if they want to navigate to the page - bugs: - - https://github.com/mozilla-mobile/fenix/issues/1857 - data_reviews: - - https://github.com/mozilla-mobile/fenix/pull/2524#issuecomment-492739967 - - https://github.com/mozilla-mobile/fenix/pull/15713#issuecomment-703972068 - data_sensitivity: - - interaction - notification_emails: - - fenix-core@mozilla.com - expires: "2021-08-01" - navigation_allowed: - type: event - description: | - A user tapped "allow" on the prompt, directing the user to the website - scanned - bugs: - - https://github.com/mozilla-mobile/fenix/issues/1857 - data_reviews: - - https://github.com/mozilla-mobile/fenix/pull/2524#issuecomment-492739967 - - https://github.com/mozilla-mobile/fenix/pull/15713#issuecomment-703972068 - data_sensitivity: - - interaction - notification_emails: - - fenix-core@mozilla.com - expires: "2021-08-01" - navigation_denied: - type: event - description: | - A user tapped "deny" on the prompt, putting the user back to the scanning - view - bugs: - - https://github.com/mozilla-mobile/fenix/issues/1857 - data_reviews: - - https://github.com/mozilla-mobile/fenix/pull/2524#issuecomment-492739967 - - https://github.com/mozilla-mobile/fenix/pull/15713#issuecomment-703972068 - data_sensitivity: - - interaction - notification_emails: - - fenix-core@mozilla.com - expires: "2021-08-01" - error_page: visited_error: type: event @@ -1858,22 +1801,6 @@ sync_auth: notification_emails: - fenix-core@mozilla.com expires: "2021-08-01" - auto_login: - type: event - description: | - User signed into FxA via an account shared from another locally installed - Mozilla application (e.g. Fennec) - bugs: - - https://github.com/mozilla-mobile/fenix/issues/4971 - data_reviews: - - https://github.com/mozilla-mobile/fenix/pull/4931#issuecomment-529740300 - - https://github.com/mozilla-mobile/fenix/pull/15713#issuecomment-703972068 - data_sensitivity: - - technical - - interaction - notification_emails: - - fenix-core@mozilla.com - expires: "2021-08-01" recovered: type: event description: | @@ -1936,20 +1863,6 @@ sync_account: notification_emails: - fenix-core@mozilla.com expires: "2021-08-01" - closed: - type: event - description: | - A user closed the sync account page - bugs: - - https://github.com/mozilla-mobile/fenix/issues/1190 - data_reviews: - - https://github.com/mozilla-mobile/fenix/pull/2745#issuecomment-494918532 - - https://github.com/mozilla-mobile/fenix/pull/15713#issuecomment-703972068 - data_sensitivity: - - interaction - notification_emails: - - fenix-core@mozilla.com - expires: "2021-08-01" sync_now: type: event description: | @@ -2306,8 +2219,7 @@ tabs_tray: save_to_collection: type: event description: | - A user tapped the save to collection button in the - three dot menu within the tabs tray + A user tapped the save to collection button in the tabs tray bugs: - https://github.com/mozilla-mobile/fenix/issues/11273 data_reviews: @@ -2591,81 +2503,7 @@ search_widget: - fenix-core@mozilla.com expires: "2021-08-01" -search_widget_cfr: - displayed: - type: event - description: | - The search widget cfr was displayed. - bugs: - - https://github.com/mozilla-mobile/fenix/issues/9488 - data_reviews: - - https://github.com/mozilla-mobile/fenix/pull/10958 - - https://github.com/mozilla-mobile/fenix/pull/15713#issuecomment-703972068 - data_sensitivity: - - interaction - notification_emails: - - fenix-core@mozilla.com - expires: "2021-08-01" - add_widget_pressed: - type: event - description: | - The user pressed the "add widget" button. - bugs: - - https://github.com/mozilla-mobile/fenix/issues/9488 - data_reviews: - - https://github.com/mozilla-mobile/fenix/pull/10958 - - https://github.com/mozilla-mobile/fenix/pull/15713#issuecomment-703972068 - data_sensitivity: - - interaction - notification_emails: - - fenix-core@mozilla.com - expires: "2021-08-01" - not_now_pressed: - type: event - description: | - The user pressed the "not now" button. - bugs: - - https://github.com/mozilla-mobile/fenix/issues/9488 - data_reviews: - - https://github.com/mozilla-mobile/fenix/pull/10958 - - https://github.com/mozilla-mobile/fenix/pull/15713#issuecomment-703972068 - data_sensitivity: - - interaction - notification_emails: - - fenix-core@mozilla.com - expires: "2021-08-01" - canceled: - type: event - description: | - The user dismissed the search widget cfr by - tapping outside of the prompt - bugs: - - https://github.com/mozilla-mobile/fenix/issues/9488 - data_reviews: - - https://github.com/mozilla-mobile/fenix/pull/10958 - - https://github.com/mozilla-mobile/fenix/pull/15713#issuecomment-703972068 - data_sensitivity: - - interaction - notification_emails: - - fenix-core@mozilla.com - expires: "2021-08-01" - private_browsing_mode: - garbage_icon: - type: event - description: | - A user pressed the garbage can icon on the private browsing home page, - deleting all private tabs. - bugs: - - https://github.com/mozilla-mobile/fenix/issues/4658 - data_reviews: - - https://github.com/mozilla-mobile/fenix/pull/4968 - - https://github.com/mozilla-mobile/fenix/pull/15713#issuecomment-703972068 - data_sensitivity: - - interaction - notification_emails: - - fenix-core@mozilla.com - expires: "2021-08-01" snackbar_undo: type: event description: | @@ -2695,35 +2533,6 @@ private_browsing_mode: notification_emails: - fenix-core@mozilla.com expires: "2021-08-01" - notification_open: - type: event - description: | - A user pressed the private browsing mode notification's "Open" button. - bugs: - - https://github.com/mozilla-mobile/fenix/issues/4658 - data_reviews: - - https://github.com/mozilla-mobile/fenix/pull/4968 - - https://github.com/mozilla-mobile/fenix/pull/15713#issuecomment-703972068 - data_sensitivity: - - interaction - notification_emails: - - fenix-core@mozilla.com - expires: "2021-08-01" - notification_delete: - type: event - description: | - A user pressed the private browsing mode notification's "Delete and Open" - button. - bugs: - - https://github.com/mozilla-mobile/fenix/issues/4658 - data_reviews: - - https://github.com/mozilla-mobile/fenix/pull/4968 - - https://github.com/mozilla-mobile/fenix/pull/15713#issuecomment-703972068 - data_sensitivity: - - interaction - notification_emails: - - fenix-core@mozilla.com - expires: "2021-08-01" contextual_hint.tracking_protection: display: diff --git a/app/src/androidTest/java/org/mozilla/fenix/glean/BaselinePingTest.kt b/app/src/androidTest/java/org/mozilla/fenix/glean/BaselinePingTest.kt index 1199adf35..afcc8d50e 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/glean/BaselinePingTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/glean/BaselinePingTest.kt @@ -110,7 +110,7 @@ class BaselinePingTest { do { attempts += 1 val request = server.takeRequest(20L, TimeUnit.SECONDS) ?: break - val docType = request.path.split("/")[3] + val docType = request.path!!.split("/")[3] if (pingName == docType) { val parsedPayload = JSONObject(request.getPlainBody()) if (pingReason == null) { diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/MockWebServer.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/MockWebServer.kt index 5dfc98ec8..5bbc5f318 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/MockWebServer.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/MockWebServer.kt @@ -39,11 +39,13 @@ object MockWebServerHelper { */ fun createAlwaysOkMockWebServer(): MockWebServer { return MockWebServer().apply { - setDispatcher(object : Dispatcher() { + val dispatcher = object : Dispatcher() { + @Throws(InterruptedException::class) override fun dispatch(request: RecordedRequest): MockResponse { return MockResponse().setBody("OK") } - }) + } + this.dispatcher = dispatcher } } } @@ -62,10 +64,10 @@ const val HTTP_NOT_FOUND = 404 class AndroidAssetDispatcher : Dispatcher() { private val mainThreadHandler = Handler(Looper.getMainLooper()) - override fun dispatch(request: RecordedRequest?): MockResponse { + override fun dispatch(request: RecordedRequest): MockResponse { val assetManager = InstrumentationRegistry.getInstrumentation().context.assets try { - val pathWithoutQueryParams = Uri.parse(request?.path?.drop(1)).path + val pathWithoutQueryParams = Uri.parse(request.path!!.drop(1)).path assetManager.open(pathWithoutQueryParams!!).use { inputStream -> return fileToResponse(pathWithoutQueryParams, inputStream) } @@ -81,7 +83,7 @@ class AndroidAssetDispatcher : Dispatcher() { private fun fileToResponse(path: String, file: InputStream): MockResponse { return MockResponse() .setResponseCode(HTTP_OK) - .setBody(fileToBytes(file)) + .setBody(fileToBytes(file)!!) .addHeader("content-type: " + contentType(path)) } diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/idlingresource/BottomSheetBehaviorStateIdlingResource.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/idlingresource/BottomSheetBehaviorStateIdlingResource.kt new file mode 100644 index 000000000..929d2e483 --- /dev/null +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/idlingresource/BottomSheetBehaviorStateIdlingResource.kt @@ -0,0 +1,56 @@ +/* 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.helpers.idlingresource + +import android.view.View +import androidx.test.espresso.IdlingResource +import androidx.test.espresso.IdlingResource.ResourceCallback +import com.google.android.material.bottomsheet.BottomSheetBehavior +import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback + +class BottomSheetBehaviorStateIdlingResource(behavior: BottomSheetBehavior<*>) : + BottomSheetCallback(), IdlingResource { + + private var isIdle: Boolean + private var callback: ResourceCallback? = null + + override fun onStateChanged(bottomSheet: View, newState: Int) { + val wasIdle = isIdle + isIdle = isIdleState(newState) + if (!wasIdle && isIdle && callback != null) { + callback!!.onTransitionToIdle() + } + } + + override fun onSlide(bottomSheet: View, slideOffset: Float) { + // no-op + } + + override fun getName(): String { + return BottomSheetBehaviorStateIdlingResource::class.java.simpleName + } + + override fun isIdleNow(): Boolean { + return isIdle + } + + override fun registerIdleTransitionCallback(callback: ResourceCallback) { + this.callback = callback + } + + private fun isIdleState(state: Int): Boolean { + return state != BottomSheetBehavior.STATE_DRAGGING && + state != BottomSheetBehavior.STATE_SETTLING && + // When detecting STATE_HALF_EXPANDED we immediately transit to STATE_HIDDEN. + // Consider this also an intermediary state so not idling. + state != BottomSheetBehavior.STATE_HALF_EXPANDED + } + + init { + behavior.addBottomSheetCallback(this) + val state = behavior.state + isIdle = isIdleState(state) + } +} diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/matchers/BottomSheetBehaviorMatchers.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/matchers/BottomSheetBehaviorMatchers.kt new file mode 100644 index 000000000..e78088eb6 --- /dev/null +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/matchers/BottomSheetBehaviorMatchers.kt @@ -0,0 +1,39 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.helpers.matchers + +import android.view.View +import androidx.test.espresso.matcher.BoundedMatcher +import com.google.android.material.bottomsheet.BottomSheetBehavior +import org.hamcrest.Description + +class BottomSheetBehaviorStateMatcher(private val expectedState: Int) : + BoundedMatcher(View::class.java) { + + override fun describeTo(description: Description?) { + description?.appendText("BottomSheetBehavior in state: \"$expectedState\"") + } + + override fun matchesSafely(item: View): Boolean { + val behavior = BottomSheetBehavior.from(item) + return behavior.state == expectedState + } +} + +class BottomSheetBehaviorHalfExpandedMaxRatioMatcher(private val maxHalfExpandedRatio: Float) : + BoundedMatcher(View::class.java) { + + override fun describeTo(description: Description?) { + description?.appendText( + "BottomSheetBehavior with an at max halfExpandedRation: " + + "$maxHalfExpandedRatio" + ) + } + + override fun matchesSafely(item: View): Boolean { + val behavior = BottomSheetBehavior.from(item) + return behavior.halfExpandedRatio <= maxHalfExpandedRatio + } +} diff --git a/app/src/androidTest/java/org/mozilla/fenix/perf/StartupExcessiveResourceUseTest.kt b/app/src/androidTest/java/org/mozilla/fenix/perf/StartupExcessiveResourceUseTest.kt new file mode 100644 index 000000000..7df918cb1 --- /dev/null +++ b/app/src/androidTest/java/org/mozilla/fenix/perf/StartupExcessiveResourceUseTest.kt @@ -0,0 +1,142 @@ +/* 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.perf + +import android.util.Log +import android.view.View +import android.view.ViewGroup +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.view.children +import androidx.recyclerview.widget.RecyclerView +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.uiautomator.UiDevice +import kotlinx.android.synthetic.main.activity_home.* +import org.junit.Assert.assertEquals +import org.junit.Rule +import org.junit.Test +import org.mozilla.fenix.ext.components +import org.mozilla.fenix.helpers.HomeActivityTestRule + +// BEFORE INCREASING THESE VALUES, PLEASE CONSULT WITH THE PERF TEAM. +private const val EXPECTED_SUPPRESSION_COUNT = 11 +private const val EXPECTED_RUNBLOCKING_COUNT = 2 +private const val EXPECTED_COMPONENT_INIT_COUNT = 42 +private const val EXPECTED_VIEW_HIERARCHY_DEPTH = 12 +private const val EXPECTED_RECYCLER_VIEW_CONSTRAINT_LAYOUT_CHILDREN = 4 + +private val failureMsgStrictMode = getErrorMessage( + shortName = "StrictMode suppression", + implications = "suppressing a StrictMode violation can introduce performance regressions?" +) + +private val failureMsgRunBlocking = getErrorMessage( + shortName = "runBlockingIncrement", + implications = "using runBlocking may block the main thread and have other negative performance implications?" +) + +private val failureMsgComponentInit = getErrorMessage( + shortName = "Component init", + implications = "initializing new components on start up may be an indication that we're doing more work than necessary on start up?" +) + +private val failureMsgViewHierarchyDepth = getErrorMessage( + shortName = "view hierarchy depth", + implications = "having a deep view hierarchy can slow down measure/layout performance?" +) + "Please note that we're not sure if this is a useful metric to assert: with your feedback, " + + "we'll find out over time if it is or is not." + +private val failureMsgRecyclerViewConstraintLayoutChildren = getErrorMessage( + shortName = "ConstraintLayout being a common direct descendant of a RecyclerView", + implications = "ConstraintLayouts are slow to inflate and are primarily used to flatten deep " + + "view hierarchies so can be under-performant as a common RecyclerView child?" +) + "Please note that we're not sure if this is a useful metric to assert: with your feedback, " + + "we'll find out over time if it is or is not." + +/** + * A performance test to limit the number of StrictMode suppressions and number of runBlocking used + * on startup. + * + * This test was written by the perf team. + * + * StrictMode detects main thread IO, which is often indicative of a performance issue. + * It's easy to suppress StrictMode so we wrote a test to ensure we have a discussion + * if the StrictMode count changes. + * + * RunBlocking is mostly used to return values to a thread from a coroutine. However, if that + * coroutine takes too long, it can lead that thread to block every other operations. + * + * The perf team is code owners for this package so they should be notified when the counts are modified. + */ +class StartupExcessiveResourceUseTest { + @get:Rule + val activityTestRule = HomeActivityTestRule(skipOnboarding = true) + + private val uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + + @Test + fun verifyRunBlockingAndStrictModeSuppresionCount() { + uiDevice.waitForIdle() // wait for async UI to load. + + // This might cause intermittents: at an arbitrary point after start up (such as the visual + // completeness queue), we might run code on the main thread that suppresses StrictMode, + // causing this number to fluctuate depending on device speed. We'll deal with it if it occurs. + val actualSuppresionCount = activityTestRule.activity.components.strictMode.suppressionCount.get().toInt() + val actualRunBlocking = RunBlockingCounter.count.get() + val actualComponentInitCount = ComponentInitCount.count.get() + + val rootView = activityTestRule.activity.rootContainer + val actualViewHierarchyDepth = countAndLogViewHierarchyDepth(rootView, 1) + val actualRecyclerViewConstraintLayoutChildren = countRecyclerViewConstraintLayoutChildren(rootView, null) + + assertEquals(failureMsgStrictMode, EXPECTED_SUPPRESSION_COUNT, actualSuppresionCount) + assertEquals(failureMsgRunBlocking, EXPECTED_RUNBLOCKING_COUNT, actualRunBlocking) + assertEquals(failureMsgComponentInit, EXPECTED_COMPONENT_INIT_COUNT, actualComponentInitCount) + assertEquals(failureMsgViewHierarchyDepth, EXPECTED_VIEW_HIERARCHY_DEPTH, actualViewHierarchyDepth) + assertEquals( + failureMsgRecyclerViewConstraintLayoutChildren, + EXPECTED_RECYCLER_VIEW_CONSTRAINT_LAYOUT_CHILDREN, + actualRecyclerViewConstraintLayoutChildren + ) + } +} + +private fun countAndLogViewHierarchyDepth(view: View, level: Int): Int { + // Log for debugging purposes: not sure if this is actually helpful. + val indent = "| ".repeat(level - 1) + Log.d("Startup...Test", "${indent}$view") + + return if (view !is ViewGroup) { + level + } else { + val maxDepth = view.children.map { countAndLogViewHierarchyDepth(it, level + 1) }.maxOrNull() + maxDepth ?: level + } +} + +private fun countRecyclerViewConstraintLayoutChildren(view: View, parent: View?): Int { + val viewValue = if (parent is RecyclerView && view is ConstraintLayout) { + 1 + } else { + 0 + } + + return if (view !is ViewGroup) { + viewValue + } else { + viewValue + view.children.sumBy { countRecyclerViewConstraintLayoutChildren(it, view) } + } +} + +private fun getErrorMessage(shortName: String, implications: String) = """$shortName count does not match expected count. + + If this PR removed a $shortName call, great! Please decrease the count. + + Did this PR add or call code that increases the $shortName count? + Did you know that $implications + Please do your best to implement a solution without adding $shortName calls. + Please consult the perf team if you have questions or believe that having this call + is the optimal solution. + +""" diff --git a/app/src/androidTest/java/org/mozilla/fenix/screenshots/MenuScreenShotTest.kt b/app/src/androidTest/java/org/mozilla/fenix/screenshots/MenuScreenShotTest.kt index c6e1e5951..3e3f2d674 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/screenshots/MenuScreenShotTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/screenshots/MenuScreenShotTest.kt @@ -43,7 +43,7 @@ class MenuScreenShotTest : ScreenshotTest() { @Before fun setUp() { mockWebServer = MockWebServer().apply { - setDispatcher(AndroidAssetDispatcher()) + dispatcher = AndroidAssetDispatcher() start() } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/syncintegration/SyncIntegrationTest.kt b/app/src/androidTest/java/org/mozilla/fenix/syncintegration/SyncIntegrationTest.kt index 283a46e05..7b6c02d16 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/syncintegration/SyncIntegrationTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/syncintegration/SyncIntegrationTest.kt @@ -44,7 +44,7 @@ class SyncIntegrationTest { @Before fun setUp() { mockWebServer = MockWebServer().apply { - setDispatcher(AndroidAssetDispatcher()) + dispatcher = AndroidAssetDispatcher() start() } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/BookmarksTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/BookmarksTest.kt index ddcdd7c84..b011e6181 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/BookmarksTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/BookmarksTest.kt @@ -12,7 +12,6 @@ import mozilla.appservices.places.BookmarkRoot import okhttp3.mockwebserver.MockWebServer import org.junit.After import org.junit.Before -import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.mozilla.fenix.R @@ -49,7 +48,7 @@ class BookmarksTest { @Before fun setUp() { mockWebServer = MockWebServer().apply { - setDispatcher(AndroidAssetDispatcher()) + dispatcher = AndroidAssetDispatcher() start() } } @@ -151,7 +150,6 @@ class BookmarksTest { } } - @Ignore("Flaky test, temp disabled: https://github.com/mozilla-mobile/fenix/issues/10690") @Test fun editBookmarkTest() { val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) @@ -164,7 +162,6 @@ class BookmarksTest { RecyclerViewIdlingResource(activityTestRule.activity.findViewById(R.id.bookmark_list), 1) IdlingRegistry.getInstance().register(bookmarksListIdlingResource!!) }.openThreeDotMenu(defaultWebPage.url) { - IdlingRegistry.getInstance().unregister(bookmarksListIdlingResource!!) }.clickEdit { verifyEditBookmarksView() verifyBookmarkNameEditBox() @@ -173,9 +170,6 @@ class BookmarksTest { changeBookmarkTitle(testBookmark.title) changeBookmarkUrl(testBookmark.url) saveEditBookmark() - - IdlingRegistry.getInstance().register(bookmarksListIdlingResource!!) - verifyBookmarkTitle(testBookmark.title) verifyBookmarkedURL(testBookmark.url) verifyKeyboardHidden() diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/ContextMenusTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/ContextMenusTest.kt index 67125a717..c877171ec 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/ContextMenusTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/ContextMenusTest.kt @@ -42,7 +42,7 @@ class ContextMenusTest { @Before fun setUp() { mockWebServer = MockWebServer().apply { - setDispatcher(AndroidAssetDispatcher()) + dispatcher = AndroidAssetDispatcher() start() } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/DeepLinkTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/DeepLinkTest.kt index 4f9a0885e..7bca26ebe 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/DeepLinkTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/DeepLinkTest.kt @@ -43,7 +43,7 @@ class DeepLinkTest { @Before fun setUp() { mockWebServer = MockWebServer().apply { - setDispatcher(AndroidAssetDispatcher()) + dispatcher = AndroidAssetDispatcher() start() } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/DownloadTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/DownloadTest.kt index cef6dbeb2..c0919cce8 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/DownloadTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/DownloadTest.kt @@ -51,7 +51,7 @@ class DownloadTest { @Before fun setUp() { mockWebServer = MockWebServer().apply { - setDispatcher(AndroidAssetDispatcher()) + dispatcher = AndroidAssetDispatcher() start() } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/HistoryTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/HistoryTest.kt index 19f97ddcb..ea6f88a16 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/HistoryTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/HistoryTest.kt @@ -41,7 +41,7 @@ class HistoryTest { @Before fun setUp() { mockWebServer = MockWebServer().apply { - setDispatcher(AndroidAssetDispatcher()) + dispatcher = AndroidAssetDispatcher() start() } } @@ -82,6 +82,7 @@ class HistoryTest { mDevice.waitForIdle() }.openThreeDotMenu { }.openHistory { + verifyHistoryListExists() historyListIdlingResource = RecyclerViewIdlingResource(activityTestRule.activity.findViewById(R.id.history_list)) IdlingRegistry.getInstance().register(historyListIdlingResource!!) @@ -101,6 +102,7 @@ class HistoryTest { mDevice.waitForIdle() }.openThreeDotMenu { }.openHistory { + verifyHistoryListExists() historyListIdlingResource = RecyclerViewIdlingResource(activityTestRule.activity.findViewById(R.id.history_list)) IdlingRegistry.getInstance().register(historyListIdlingResource!!) @@ -119,6 +121,7 @@ class HistoryTest { mDevice.waitForIdle() }.openThreeDotMenu { }.openHistory { + verifyHistoryListExists() historyListIdlingResource = RecyclerViewIdlingResource(activityTestRule.activity.findViewById(R.id.history_list)) IdlingRegistry.getInstance().register(historyListIdlingResource!!) @@ -140,6 +143,7 @@ class HistoryTest { mDevice.waitForIdle() }.openThreeDotMenu { }.openHistory { + verifyHistoryListExists() historyListIdlingResource = RecyclerViewIdlingResource(activityTestRule.activity.findViewById(R.id.history_list)) IdlingRegistry.getInstance().register(historyListIdlingResource!!) @@ -160,6 +164,7 @@ class HistoryTest { mDevice.waitForIdle() }.openThreeDotMenu { }.openHistory { + verifyHistoryListExists() historyListIdlingResource = RecyclerViewIdlingResource(activityTestRule.activity.findViewById(R.id.history_list)) IdlingRegistry.getInstance().register(historyListIdlingResource!!) @@ -180,6 +185,7 @@ class HistoryTest { mDevice.waitForIdle() }.openThreeDotMenu { }.openHistory { + verifyHistoryListExists() historyListIdlingResource = RecyclerViewIdlingResource(activityTestRule.activity.findViewById(R.id.history_list)) IdlingRegistry.getInstance().register(historyListIdlingResource!!) @@ -200,6 +206,7 @@ class HistoryTest { mDevice.waitForIdle() }.openThreeDotMenu { }.openHistory { + verifyHistoryListExists() historyListIdlingResource = RecyclerViewIdlingResource(activityTestRule.activity.findViewById(R.id.history_list)) IdlingRegistry.getInstance().register(historyListIdlingResource!!) @@ -221,6 +228,7 @@ class HistoryTest { mDevice.waitForIdle() }.openThreeDotMenu { }.openHistory { + verifyHistoryListExists() historyListIdlingResource = RecyclerViewIdlingResource(activityTestRule.activity.findViewById(R.id.history_list)) IdlingRegistry.getInstance().register(historyListIdlingResource!!) @@ -250,6 +258,7 @@ class HistoryTest { homeScreen { }.openThreeDotMenu { }.openHistory { + verifyHistoryListExists() historyListIdlingResource = RecyclerViewIdlingResource(activityTestRule.activity.findViewById(R.id.history_list)) IdlingRegistry.getInstance().register(historyListIdlingResource!!) @@ -273,6 +282,7 @@ class HistoryTest { mDevice.waitForIdle() }.openThreeDotMenu { }.openHistory { + verifyHistoryListExists() historyListIdlingResource = RecyclerViewIdlingResource(activityTestRule.activity.findViewById(R.id.history_list)) IdlingRegistry.getInstance().register(historyListIdlingResource!!) @@ -299,6 +309,7 @@ class HistoryTest { }.submitQuery(secondWebPage.url.toString()) { }.openThreeDotMenu { }.openHistory { + verifyHistoryListExists() historyListIdlingResource = RecyclerViewIdlingResource(activityTestRule.activity.findViewById(R.id.history_list), 1) IdlingRegistry.getInstance().register(historyListIdlingResource!!) @@ -326,6 +337,7 @@ class HistoryTest { mDevice.waitForIdle() }.openThreeDotMenu { }.openHistory { + verifyHistoryListExists() historyListIdlingResource = RecyclerViewIdlingResource(activityTestRule.activity.findViewById(R.id.history_list)) IdlingRegistry.getInstance().register(historyListIdlingResource!!) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/HomeScreenTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/HomeScreenTest.kt index 65beff57c..9932c9aa3 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/HomeScreenTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/HomeScreenTest.kt @@ -13,7 +13,6 @@ import androidx.test.uiautomator.By import androidx.test.uiautomator.Until import org.mozilla.fenix.helpers.ext.waitNotNull import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime -import org.mozilla.fenix.ui.robots.PRIVATE_SESSION_MESSAGE import org.mozilla.fenix.ui.robots.homeScreen /** @@ -54,68 +53,6 @@ class HomeScreenTest { } } - @Test - fun firstRunScreenTest() { - homeScreen { - verifyHomeScreen() - verifyNavigationToolbar() - verifyHomePrivateBrowsingButton() - verifyHomeMenu() - verifyHomeWordmark() - - verifyWelcomeHeader() - // Sign in to Firefox - verifyGetTheMostHeader() - verifyAccountsSignInButton() - - // Intro to other sections - verifyGetToKnowHeader() - - // See What's new - // scrollToElementByText("See what’s new") - // verifyWhatsNewHeader() - // verifyWhatsNewLink() - - // Automatic privacy - scrollToElementByText("Automatic privacy") - verifyAutomaticPrivacyfHeader() - verifyTrackingProtectionToggle() - verifyAutomaticPrivacyText() - - /* Check disable due to Firebase failures on Pixel 2 API 28 - // Choose your theme - verifyChooseThemeHeader() - verifyChooseThemeText() - verifyDarkThemeDescription() - verifyDarkThemeToggle() - verifyLightThemeDescription() - verifyLightThemeToggle() - - // Browse privately - scrollToElementByText("Open Settings") - verifyBrowsePrivatelyHeader() - verifyBrowsePrivatelyText() - */ - - swipeToBottom() - - // Take a position - scrollToElementByText("Take a position") - verifyTakePositionHeader() - verifyTakePositionElements() - - // Your privacy - scrollToElementByText("Your privacy") - verifyYourPrivacyHeader() - verifyYourPrivacyText() - verifyPrivacyNoticeButton() - - // Start Browsing - swipeToBottom() - verifyStartBrowsingButton() - } - } - @Test fun privateModeScreenItemsTest() { homeScreen { }.dismissOnboarding() @@ -136,7 +73,7 @@ class HomeScreenTest { homeScreen { // To deal with the race condition where multiple "add tab" buttons are present, // we need to wait until previous HomeFragment View objects are gone. - mDevice.waitNotNull(Until.gone(By.text(PRIVATE_SESSION_MESSAGE)), waitingTime) + mDevice.waitNotNull(Until.gone(By.text(privateSessionMessage)), waitingTime) verifyHomeScreen() verifyNavigationToolbar() verifyHomePrivateBrowsingButton() diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/MediaNotificationTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/MediaNotificationTest.kt index 5f3baff90..02ce669f2 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/MediaNotificationTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/MediaNotificationTest.kt @@ -37,7 +37,7 @@ class MediaNotificationTest { @Before fun setUp() { mockWebServer = MockWebServer().apply { - setDispatcher(AndroidAssetDispatcher()) + dispatcher = AndroidAssetDispatcher() start() } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/NavigationToolbarTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/NavigationToolbarTest.kt index 65e850860..ae9c165e6 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/NavigationToolbarTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/NavigationToolbarTest.kt @@ -38,7 +38,7 @@ class NavigationToolbarTest { @Before fun setUp() { mockWebServer = MockWebServer().apply { - setDispatcher(AndroidAssetDispatcher()) + dispatcher = AndroidAssetDispatcher() start() } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/ReaderViewTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/ReaderViewTest.kt index 4e08cbc41..e73ac0182 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/ReaderViewTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/ReaderViewTest.kt @@ -41,7 +41,7 @@ class ReaderViewTest { @Before fun setUp() { mockWebServer = MockWebServer().apply { - setDispatcher(AndroidAssetDispatcher()) + dispatcher = AndroidAssetDispatcher() start() } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAboutTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAboutTest.kt index 26368bd0a..ba101f0c9 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAboutTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAboutTest.kt @@ -33,7 +33,7 @@ class SettingsAboutTest { @Before fun setUp() { mockWebServer = MockWebServer().apply { - setDispatcher(AndroidAssetDispatcher()) + dispatcher = AndroidAssetDispatcher() start() } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAddonsTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAddonsTest.kt index 12b74d038..79057f88c 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAddonsTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAddonsTest.kt @@ -39,7 +39,7 @@ class SettingsAddonsTest { @Before fun setUp() { mockWebServer = MockWebServer().apply { - setDispatcher(AndroidAssetDispatcher()) + dispatcher = AndroidAssetDispatcher() start() } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAdvancedTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAdvancedTest.kt index 381cc9862..c12669080 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAdvancedTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAdvancedTest.kt @@ -32,7 +32,7 @@ class SettingsAdvancedTest { @Before fun setUp() { mockWebServer = MockWebServer().apply { - setDispatcher(AndroidAssetDispatcher()) + dispatcher = AndroidAssetDispatcher() start() } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsBasicsTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsBasicsTest.kt index 3e43e80b7..ebafc68ac 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsBasicsTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsBasicsTest.kt @@ -39,7 +39,7 @@ class SettingsBasicsTest { @Before fun setUp() { mockWebServer = MockWebServer().apply { - setDispatcher(AndroidAssetDispatcher()) + dispatcher = AndroidAssetDispatcher() start() } } @@ -204,7 +204,7 @@ class SettingsBasicsTest { checkTextSizeOnWebsite(textSizePercentage, fenixApp.components) }.openTabDrawer { }.openNewTab { - }.dismiss { + }.dismissSearchBar { }.openThreeDotMenu { }.openSettings { }.openAccessibilitySubMenu { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsDeveloperToolsTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsDeveloperToolsTest.kt index f42902c99..c7cfed81f 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsDeveloperToolsTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsDeveloperToolsTest.kt @@ -33,7 +33,7 @@ class SettingsDeveloperToolsTest { @Before fun setUp() { mockWebServer = MockWebServer().apply { - setDispatcher(AndroidAssetDispatcher()) + dispatcher = AndroidAssetDispatcher() start() } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsPrivacyTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsPrivacyTest.kt index 78802cda9..c5afc8303 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsPrivacyTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsPrivacyTest.kt @@ -41,7 +41,7 @@ class SettingsPrivacyTest { @Before fun setUp() { mockWebServer = MockWebServer().apply { - setDispatcher(AndroidAssetDispatcher()) + dispatcher = AndroidAssetDispatcher() start() } } @@ -197,7 +197,7 @@ class SettingsPrivacyTest { saveLoginFromPrompt("Save") }.openTabDrawer { }.openNewTab { - }.dismiss { + }.dismissSearchBar { }.openThreeDotMenu { }.openSettings { TestHelper.scrollToElementByText("Logins and passwords") @@ -223,7 +223,7 @@ class SettingsPrivacyTest { saveLoginFromPrompt("Never save") }.openTabDrawer { }.openNewTab { - }.dismiss { + }.dismissSearchBar { }.openThreeDotMenu { }.openSettings { }.openLoginsAndPasswordSubMenu { @@ -278,7 +278,7 @@ class SettingsPrivacyTest { browserScreen { }.openTabDrawer { verifyPrivateModeSelected() - }.openNewTab { }.dismiss { } + }.openNewTab { }.dismissSearchBar { } setOpenLinksInPrivateOff() @@ -325,7 +325,7 @@ class SettingsPrivacyTest { clickAddAutomaticallyButton() }.openHomeScreenShortcut(pageShortcutName) { }.openTabDrawer { - }.openNewTab { }.dismiss { } + }.openNewTab { }.dismissSearchBar { } setOpenLinksInPrivateOff() restartApp(activityTestRule) @@ -336,7 +336,7 @@ class SettingsPrivacyTest { }.openTabDrawer { verifyNormalModeSelected() }.openNewTab { - }.dismiss { + }.dismissSearchBar { }.openThreeDotMenu { }.openSettings { }.openPrivateBrowsingSubMenu { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsSyncTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsSyncTest.kt index 21ce9cf77..55bd79651 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsSyncTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsSyncTest.kt @@ -32,7 +32,7 @@ class SettingsSyncTest { @Before fun setUp() { mockWebServer = MockWebServer().apply { - setDispatcher(AndroidAssetDispatcher()) + dispatcher = AndroidAssetDispatcher() start() } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsTest.kt index ebb66370a..2672d1afd 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsTest.kt @@ -32,7 +32,7 @@ class SettingsTest { @Before fun setUp() { mockWebServer = MockWebServer().apply { - setDispatcher(AndroidAssetDispatcher()) + dispatcher = AndroidAssetDispatcher() start() } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/ShareButtonTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/ShareButtonTest.kt index f8f942035..bc9767cdb 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/ShareButtonTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/ShareButtonTest.kt @@ -33,7 +33,7 @@ class ShareButtonTest { @Before fun setUp() { mockWebServer = MockWebServer().apply { - setDispatcher(AndroidAssetDispatcher()) + dispatcher = AndroidAssetDispatcher() start() } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt index 695fac0d0..55e13cf94 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt @@ -4,12 +4,12 @@ package org.mozilla.fenix.ui +import androidx.core.net.toUri import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import okhttp3.mockwebserver.MockWebServer import org.junit.After import org.junit.Before -import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.mozilla.fenix.helpers.AndroidAssetDispatcher @@ -34,7 +34,7 @@ class SmokeTest { @Before fun setUp() { mockWebServer = MockWebServer().apply { - setDispatcher(AndroidAssetDispatcher()) + dispatcher = AndroidAssetDispatcher() start() } } @@ -44,6 +44,56 @@ class SmokeTest { mockWebServer.shutdown() } + // copied over from HomeScreenTest + @Test + fun firstRunScreenTest() { + homeScreen { + verifyHomeScreen() + verifyNavigationToolbar() + verifyHomePrivateBrowsingButton() + verifyHomeMenu() + verifyHomeWordmark() + + verifyWelcomeHeader() + // Sign in to Firefox + verifyStartSyncHeader() + verifyAccountsSignInButton() + + // Intro to other sections + verifyGetToKnowHeader() + + // Automatic privacy + scrollToElementByText("Automatic privacy") + verifyAutomaticPrivacyHeader() + verifyTrackingProtectionToggle() + verifyAutomaticPrivacyText() + + // Choose your theme + verifyChooseThemeHeader() + verifyChooseThemeText() + verifyDarkThemeDescription() + verifyDarkThemeToggle() + verifyLightThemeDescription() + verifyLightThemeToggle() + + // Browse privately + verifyBrowsePrivatelyHeader() + verifyBrowsePrivatelyText() + + // Take a position + verifyTakePositionHeader() + verifyTakePositionElements() + + // Your privacy + verifyYourPrivacyHeader() + verifyYourPrivacyText() + verifyPrivacyNoticeButton() + + // Start Browsing + verifyStartBrowsingButton() + } + } + @Test fun verifyBasicNavigationToolbarFunctionality() { val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) @@ -58,15 +108,14 @@ class SmokeTest { }.openTabDrawer { verifyExistingTabList() }.openNewTab { - }.dismiss { + }.dismissSearchBar { verifyHomeScreen() } } } - @Ignore("Failing, see: https://github.com/mozilla-mobile/fenix/issues/13217") @Test - fun verifyPageMainMenuItemsListInPortraitNormalModeTest() { + fun verifyPageMainMenuItemsTest() { val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) // Add this to check openInApp and youtube is a default app available in every Android emulator/device val youtubeUrl = "www.youtube.com" @@ -75,24 +124,16 @@ class SmokeTest { }.enterURLAndEnterToBrowser(defaultWebPage.url) { }.openThreeDotMenu { verifyThreeDotMainMenuItems() - verifySaveCollection() - }.clickAddOnsReportSiteIssue { - verifyUrl("webcompat.com/issues/new") - }.openTabDrawer { - }.openTab(defaultWebPage.title) { - }.openThreeDotMenu { }.openHistory { - verifyTestPageUrl(defaultWebPage.url) + verifyHistoryMenuView() }.goBackToBrowser { }.openThreeDotMenu { }.openBookmarks { verifyBookmarksMenuView() - verifyEmptyBookmarksList() }.goBackToBrowser { }.openThreeDotMenu { }.openSyncedTabs { - verifyNavigationToolBarHeader() - verifySyncedTabsStatus() + verifySyncedTabsMenuHeader() }.goBack { }.openThreeDotMenu { }.openSettings { @@ -107,7 +148,7 @@ class SmokeTest { verifySnackBarText("Added to top sites!") }.openTabDrawer { }.openNewTab { - }.dismiss { + }.dismissSearchBar { verifyExistingTopSitesTabs(defaultWebPage.title) }.openTabDrawer { }.openTab(defaultWebPage.title) { @@ -120,7 +161,7 @@ class SmokeTest { }.openThreeDotMenu { }.openSaveToCollection { verifyCollectionNameTextField() - }.goBackToBrowser { + }.exitSaveCollection { }.openThreeDotMenu { }.bookmarkPage { verifySnackBarText("Bookmark saved!") @@ -131,96 +172,15 @@ class SmokeTest { }.openThreeDotMenu { }.refreshPage { verifyUrl(defaultWebPage.url.toString()) - }.openTabDrawer { - closeTabViaXButton(defaultWebPage.title) - }.openNewTab { - }.submitQuery(youtubeUrl) { - verifyBlueDot() + }.openNavigationToolbar { + }.enterURLAndEnterToBrowser(youtubeUrl.toUri()) { }.openThreeDotMenu { verifyOpenInAppButton() } } - @Ignore("Failing, see: https://github.com/mozilla-mobile/fenix/issues/13217") - @Test - fun verifyPageMainMenuItemsListInPortraitPrivateModeTest() { - val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) - // Add this to check openInApp and also youtube is a default app available in every Android emulator/device - val youtubeUrl = "www.youtube.com" - - homeScreen { - togglePrivateBrowsingModeOnOff() - navigationToolbar { - }.enterURLAndEnterToBrowser(defaultWebPage.url) { - }.openThreeDotMenu { - verifyThreeDotMainMenuItems() - }.clickAddOnsReportSiteIssue { - verifyUrl("webcompat.com/issues/new") - }.openTabDrawer { - }.openTab(defaultWebPage.title) { - }.openThreeDotMenu { - }.openHistory { - verifyEmptyHistoryView() - }.goBackToBrowser { - }.openThreeDotMenu { - }.openBookmarks { - verifyBookmarksMenuView() - verifyEmptyBookmarksList() - }.goBackToBrowser { - }.openThreeDotMenu { - }.openSyncedTabs { - verifyNavigationToolBarHeader() - verifySyncedTabsStatus() - }.goBack { - }.openThreeDotMenu { - }.openSettings { - verifySettingsView() - }.goBackToBrowser { - }.openThreeDotMenu { - }.openFindInPage { - verifyFindInPageSearchBarItems() - }.closeFindInPage { - }.openThreeDotMenu { - }.addToFirefoxHome { - verifySnackBarText("Added to top sites!") - }.openTabDrawer { - }.openNewTab { - }.dismiss { - togglePrivateBrowsingModeOnOff() - verifyExistingTopSitesTabs(defaultWebPage.title) - togglePrivateBrowsingModeOnOff() - }.openTabDrawer { - }.openTab(defaultWebPage.title) { - }.openThreeDotMenu { - }.openAddToHomeScreen { - verifyShortcutNameField(defaultWebPage.title) - clickAddShortcutButton() - clickAddAutomaticallyButton() - }.openHomeScreenShortcut(defaultWebPage.title) { - }.openThreeDotMenu { - }.bookmarkPage { - verifySnackBarText("Bookmark saved!") - }.openThreeDotMenu { - }.sharePage { - verifyShareAppsLayout() - }.closeShareDialogReturnToPage { - }.openThreeDotMenu { - }.refreshPage { - verifyUrl(defaultWebPage.url.toString()) - }.openTabDrawer { - closeTabViaXButton(defaultWebPage.title) - }.openNewTab { - }.submitQuery(youtubeUrl) { - verifyBlueDot() - }.openThreeDotMenu { - verifyOpenInAppButton() - } - } - } - - @Ignore("Flaky test: https://github.com/mozilla-mobile/fenix/issues/12899") @Test - fun verifyETPToolbarShieldIconIsNotDisplayedIfETPIsOFFGloballyTest() { + fun verifyETPShieldNotDisplayedIfOFFGlobally() { val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) homeScreen { @@ -234,19 +194,11 @@ class SmokeTest { }.enterURLAndEnterToBrowser(defaultWebPage.url) { verifyEnhancedTrackingProtectionPanelNotVisible() }.openThreeDotMenu { - }.clickAddOnsReportSiteIssue { - verifyUrl("webcompat.com/issues/new") - verifyTabCounter("2") - }.openTabDrawer { - }.openNewTab { - }.dismiss { - }.openThreeDotMenu { }.openSettings { }.openEnhancedTrackingProtectionSubMenu { clickEnhancedTrackingProtectionDefaults() - }.goBackToHomeScreen { - }.openTabDrawer { - }.openTab(defaultWebPage.title) { + }.goBack { + }.goBackToBrowser { clickEnhancedTrackingProtectionPanel() verifyEnhancedTrackingProtectionSwitch() // Turning off TP Switch results in adding the WebPage to exception list diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/StrictEnhancedTrackingProtectionTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/StrictEnhancedTrackingProtectionTest.kt index 86f5c929f..659f7547e 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/StrictEnhancedTrackingProtectionTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/StrictEnhancedTrackingProtectionTest.kt @@ -42,7 +42,7 @@ class StrictEnhancedTrackingProtectionTest { @Before fun setUp() { mockWebServer = MockWebServer().apply { - setDispatcher(AndroidAssetDispatcher()) + dispatcher = AndroidAssetDispatcher() start() } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/StrictModeStartupSuppressionCountTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/StrictModeStartupSuppressionCountTest.kt deleted file mode 100644 index ece75c63d..000000000 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/StrictModeStartupSuppressionCountTest.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* 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.ui - -import androidx.test.platform.app.InstrumentationRegistry -import androidx.test.uiautomator.UiDevice -import org.junit.Assert.assertEquals -import org.junit.Rule -import org.junit.Test -import org.mozilla.fenix.ext.components -import org.mozilla.fenix.helpers.HomeActivityTestRule - -// PLEASE CONSULT WITH PERF TEAM BEFORE CHANGING THIS VALUE. -private const val EXPECTED_SUPPRESSION_COUNT = 11 - -private const val FAILURE_MSG = """StrictMode startup suppression count does not match expected count. - - If this PR removed code that suppressed StrictMode, great! Please decrement the suppression count. - - Did this PR add or call code that suppresses a StrictMode violation? - Did you know that suppressing a StrictMode violation can introduce performance regressions? - - If so, please do your best to implement a solution without suppressing StrictMode. - Please consult the perf team if you have questions or believe suppressing StrictMode - is the optimal solution. - -""" - -/** - * A performance test to limit the number of StrictMode suppressions on startup. - * This test was written by the perf team. - * - * StrictMode detects main thread IO, which is often indicative of a performance issue. - * It's easy to suppress StrictMode so we wrote a test to ensure we have a discussion - * if the StrictMode count changes. The perf team is code owners for this file so they - * should be notified when the count is modified. - * - * IF YOU UPDATE THE TEST NAME, UPDATE CODE OWNERS. - */ -class StrictModeStartupSuppressionCountTest { - @get:Rule - val activityTestRule = HomeActivityTestRule(skipOnboarding = true) - - private val uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) - - @Test - fun verifyStrictModeSuppressionCount() { - uiDevice.waitForIdle() // wait for async UI to load. - - // This might cause intermittents: at an arbitrary point after start up (such as the visual - // completeness queue), we might run code on the main thread that suppresses StrictMode, - // causing this number to fluctuate depending on device speed. We'll deal with it if it occurs. - val actual = activityTestRule.activity.components.strictMode.suppressionCount.toInt() - assertEquals(FAILURE_MSG, EXPECTED_SUPPRESSION_COUNT, actual) - } -} diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt index bebecaba5..24d78cc61 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt @@ -6,6 +6,7 @@ package org.mozilla.fenix.ui import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice +import com.google.android.material.bottomsheet.BottomSheetBehavior import okhttp3.mockwebserver.MockWebServer import org.junit.After import org.junit.Before @@ -49,7 +50,7 @@ class TabbedBrowsingTest { @Before fun setUp() { mockWebServer = MockWebServer().apply { - setDispatcher(AndroidAssetDispatcher()) + dispatcher = AndroidAssetDispatcher() start() } } @@ -84,7 +85,7 @@ class TabbedBrowsingTest { }.openTabsListThreeDotMenu { verifyCloseAllTabsButton() verifyShareTabButton() - verifySaveCollection() + verifySelectTabs() } } @@ -126,7 +127,7 @@ class TabbedBrowsingTest { }.openTabsListThreeDotMenu { verifyCloseAllTabsButton() verifyShareTabButton() - verifySaveCollection() + verifySelectTabs() }.closeAllTabs { verifyNoTabsOpened() } @@ -187,7 +188,7 @@ class TabbedBrowsingTest { }.openTabDrawer { verifyExistingOpenTabs("Test_Page_1") }.openNewTab { - }.dismiss { } + }.dismissSearchBar { } } @Test @@ -254,6 +255,31 @@ class TabbedBrowsingTest { } } + @Test + fun verifyTabTrayNotShowingStateHalfExpanded() { + homeScreen { }.dismissOnboarding() + + navigationToolbar { + }.openTabTray { + verifyNoTabsOpened() + // With no tabs opened the state should be STATE_COLLAPSED. + verifyBehaviorState(BottomSheetBehavior.STATE_COLLAPSED) + // Need to ensure the halfExpandedRatio is very small so that when in STATE_HALF_EXPANDED + // the tabTray will actually have a very small height (for a very short time) akin to being hidden. + verifyHalfExpandedRatio() + }.clickTopBar { + }.waitForTabTrayBehaviorToIdle { + // Touching the topBar would normally advance the tabTray to the next state. + // We don't want that. + verifyBehaviorState(BottomSheetBehavior.STATE_COLLAPSED) + }.advanceToHalfExpandedState { + }.waitForTabTrayBehaviorToIdle { + // TabTray should not be displayed in STATE_HALF_EXPANDED. + // When advancing to this state it should immediately be hidden. + verifyTabTrayIsClosed() + } + } + @Test fun verifyEmptyTabTray() { homeScreen { }.dismissOnboarding() @@ -286,7 +312,7 @@ class TabbedBrowsingTest { verifyExistingOpenTabs(defaultWebPage.title) verifyCloseTabsButton(defaultWebPage.title) }.openNewTab { - }.dismiss { } + }.dismissSearchBar { } } @Test diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/ThreeDotMenuMainTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/ThreeDotMenuMainTest.kt index 59e392a06..ca48ce5b6 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/ThreeDotMenuMainTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/ThreeDotMenuMainTest.kt @@ -32,7 +32,7 @@ class ThreeDotMenuMainTest { @Before fun setUp() { mockWebServer = MockWebServer().apply { - setDispatcher(AndroidAssetDispatcher()) + dispatcher = AndroidAssetDispatcher() start() } } @@ -69,13 +69,13 @@ class ThreeDotMenuMainTest { verifyHelpUrl() }.openTabDrawer { }.openNewTab { - }.dismiss { + }.dismissSearchBar { }.openThreeDotMenu { }.openWhatsNew { verifyWhatsNewURL() }.openTabDrawer { }.openNewTab { - }.dismiss { } + }.dismissSearchBar { } homeScreen { }.openThreeDotMenu { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/TopSitesTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/TopSitesTest.kt index 674e767c2..4f5a4bbc1 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/TopSitesTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/TopSitesTest.kt @@ -36,7 +36,7 @@ class TopSitesTest { @Before fun setUp() { mockWebServer = MockWebServer().apply { - setDispatcher(AndroidAssetDispatcher()) + dispatcher = AndroidAssetDispatcher() start() } } @@ -59,7 +59,7 @@ class TopSitesTest { verifySnackBarText("Added to top sites!") }.openTabDrawer { }.openNewTab { - }.dismiss { + }.dismissSearchBar { verifyExistingTopSitesList() verifyExistingTopSitesTabs(defaultWebPageTitle) } @@ -78,14 +78,14 @@ class TopSitesTest { verifySnackBarText("Added to top sites!") }.openTabDrawer { }.openNewTab { - }.dismiss { + }.dismissSearchBar { verifyExistingTopSitesList() verifyExistingTopSitesTabs(defaultWebPageTitle) }.openTopSiteTabWithTitle(title = defaultWebPageTitle) { verifyUrl(defaultWebPage.url.toString().replace("http://", "")) }.openTabDrawer { }.openNewTab { - }.dismiss { + }.dismissSearchBar { verifyExistingTopSitesList() verifyExistingTopSitesTabs(defaultWebPageTitle) }.openContextMenuOnTopSitesWithTitle(defaultWebPageTitle) { @@ -109,7 +109,7 @@ class TopSitesTest { verifySnackBarText("Added to top sites!") }.openTabDrawer { }.openNewTab { - }.dismiss { + }.dismissSearchBar { verifyExistingTopSitesList() verifyExistingTopSitesTabs(defaultWebPageTitle) }.openContextMenuOnTopSitesWithTitle(defaultWebPageTitle) { @@ -119,6 +119,31 @@ class TopSitesTest { } } + @Test + fun verifyRenameTopSite() { + val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) + val defaultWebPageTitle = "Test_Page_1" + val defaultWebPageTitleNew = "Test_Page_2" + + navigationToolbar { + }.enterURLAndEnterToBrowser(defaultWebPage.url) { + }.openThreeDotMenu { + verifyAddFirefoxHome() + }.addToFirefoxHome { + verifySnackBarText("Added to top sites!") + }.openTabDrawer { + }.openNewTab { + }.dismissSearchBar { + verifyExistingTopSitesList() + verifyExistingTopSitesTabs(defaultWebPageTitle) + }.openContextMenuOnTopSitesWithTitle(defaultWebPageTitle) { + verifyTopSiteContextMenuItems() + }.renameTopSite(defaultWebPageTitleNew) { + verifyExistingTopSitesList() + verifyExistingTopSitesTabs(defaultWebPageTitleNew) + } + } + @Test fun verifyRemoveTopSite() { val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) @@ -132,7 +157,7 @@ class TopSitesTest { verifySnackBarText("Added to top sites!") }.openTabDrawer { }.openNewTab { - }.dismiss { + }.dismissSearchBar { verifyExistingTopSitesList() verifyExistingTopSitesTabs(defaultWebPageTitle) }.openContextMenuOnTopSitesWithTitle(defaultWebPageTitle) { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BookmarksRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BookmarksRobot.kt index bd5a17f06..36b014071 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BookmarksRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BookmarksRobot.kt @@ -27,7 +27,6 @@ import androidx.test.uiautomator.By import androidx.test.uiautomator.Until import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.By.res -import androidx.test.uiautomator.By.text import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.UiSelector import org.hamcrest.Matchers.allOf @@ -44,7 +43,13 @@ import org.mozilla.fenix.helpers.ext.waitNotNull */ class BookmarksRobot { - fun verifyBookmarksMenuView() = assertBookmarksView() + fun verifyBookmarksMenuView() { + mDevice.findObject( + UiSelector().text("Bookmarks") + ).waitForExists(waitingTime) + + assertBookmarksView() + } fun verifyEmptyBookmarksList() = assertEmptyBookmarksList() @@ -58,10 +63,7 @@ class BookmarksRobot { } fun verifyBookmarkTitle(title: String) { - mDevice.waitNotNull( - Until.findObject(text(title)), - TestAssetHelper.waitingTime - ) + mDevice.findObject(UiSelector().text(title)).waitForExists(waitingTime) assertBookmarkTitle(title) } @@ -164,7 +166,7 @@ class BookmarksRobot { fun saveEditBookmark() { saveBookmarkButton().click() - mDevice.waitNotNull(Until.findObject(text("Bookmarks"))) + mDevice.findObject(UiSelector().resourceId("R.id.bookmark_list")).waitForExists(waitingTime) } fun clickParentFolderSelector() = bookmarkFolderSelector().click() diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BrowserRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BrowserRobot.kt index 771b4fddf..dcf84c575 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BrowserRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BrowserRobot.kt @@ -33,6 +33,7 @@ import androidx.test.uiautomator.UiSelector import androidx.test.uiautomator.Until import org.hamcrest.CoreMatchers.allOf import org.hamcrest.CoreMatchers.containsString +import org.hamcrest.Matchers.not import org.junit.Assert.assertTrue import org.mozilla.fenix.R import org.mozilla.fenix.ext.components @@ -155,8 +156,6 @@ class BrowserRobot { fun verifyMenuButton() = assertMenuButton() - fun verifyBlueDot() = assertBlueDot() - fun verifyNavURLBarItems() { verifyEnhancedTrackingOptions() pressBack() @@ -187,10 +186,10 @@ class BrowserRobot { .perform(ViewActions.pressBack()) } - fun clickEnhancedTrackingProtectionPanel() = enhancedTrackingProtectionPanel().click() + fun clickEnhancedTrackingProtectionPanel() = enhancedTrackingProtectionIndicator().click() fun verifyEnhancedTrackingProtectionPanelNotVisible() = - assertEnhancedTrackingProtectionPanelNotVisible() + assertEnhancedTrackingProtectionIndicatorNotVisible() fun clickContextOpenLinkInNewTab() { val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) @@ -415,12 +414,11 @@ fun navURLBar() = onView(withId(R.id.mozac_browser_toolbar_url_view)) private fun assertNavURLBar() = navURLBar() .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) -fun enhancedTrackingProtectionPanel() = +fun enhancedTrackingProtectionIndicator() = onView(withId(R.id.mozac_browser_toolbar_tracking_protection_indicator)) -private fun assertEnhancedTrackingProtectionPanelNotVisible() { - enhancedTrackingProtectionPanel() - .check(matches(withEffectiveVisibility(Visibility.GONE))) +private fun assertEnhancedTrackingProtectionIndicatorNotVisible() { + enhancedTrackingProtectionIndicator().check(matches(not(isDisplayed()))) } private fun assertEnhancedTrackingProtectionSwitch() { @@ -453,10 +451,3 @@ private fun mediaPlayerPlayButton() = .className("android.widget.Button") .text("Play") ) - -private fun assertBlueDot() { - onView(withId(R.id.notification_dot)) - .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) -} - -private fun addOnsReportSiteIssue() = onView(withText("Report Site Issue")) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HistoryRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HistoryRobot.kt index 60a96e96d..c7eb8dcec 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HistoryRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HistoryRobot.kt @@ -39,6 +39,8 @@ class HistoryRobot { assertEmptyHistoryView() } + fun verifyHistoryListExists() = assertHistoryListExists() + fun verifyVisitedTimeTitle() { mDevice.waitNotNull( Until.findObject( @@ -85,6 +87,8 @@ class HistoryRobot { class Transition { fun goBackToBrowser(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition { + mDevice.pressBack() + BrowserRobot().interact() return BrowserRobot.Transition() } @@ -131,6 +135,9 @@ private fun assertEmptyHistoryView() = ) .check(matches(withText("No history here"))) +private fun assertHistoryListExists() = + mDevice.findObject(UiSelector().resourceId("R.id.history_list")).waitForExists(waitingTime) + private fun assertVisitedTimeTitle() = onView(withId(R.id.header_title)).check(matches(withText("Today"))) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HomeScreenRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HomeScreenRobot.kt index b9edac4a2..a68b19f32 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HomeScreenRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HomeScreenRobot.kt @@ -7,6 +7,7 @@ package org.mozilla.fenix.ui.robots import android.graphics.Bitmap +import android.widget.EditText import androidx.recyclerview.widget.RecyclerView import androidx.test.espresso.Espresso.onView import androidx.test.espresso.NoMatchingViewException @@ -36,14 +37,18 @@ import androidx.test.uiautomator.UiScrollable import androidx.test.uiautomator.UiSelector import androidx.test.uiautomator.Until import androidx.test.uiautomator.Until.findObject +import mozilla.components.support.ktx.android.content.appName import org.hamcrest.CoreMatchers.allOf import org.hamcrest.CoreMatchers.containsString +import org.hamcrest.CoreMatchers.instanceOf import org.hamcrest.CoreMatchers.not +import org.hamcrest.Matchers import org.junit.Assert import org.mozilla.fenix.R import org.mozilla.fenix.components.Search import org.mozilla.fenix.helpers.TestAssetHelper import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime +import org.mozilla.fenix.helpers.TestHelper.scrollToElementByText import org.mozilla.fenix.helpers.click import org.mozilla.fenix.helpers.ext.waitNotNull import org.mozilla.fenix.helpers.matchers.hasItem @@ -53,6 +58,12 @@ import org.mozilla.fenix.helpers.withBitmapDrawable * Implementation of Robot Pattern for the home screen menu. */ class HomeScreenRobot { + val privateSessionMessage = + "${appContext.appName} clears your search and browsing history from private tabs when you close them" + + " or quit the app. While this doesn’t make you anonymous to websites or your internet" + + " service provider, it makes it easier to keep what you do online private from anyone" + + " else who uses this device." + fun verifyNavigationToolbar() = assertNavigationToolbar() fun verifyFocusedNavigationToolbar() = assertFocusedNavigationToolbar() fun verifyHomeScreen() = assertHomeScreen() @@ -72,7 +83,7 @@ class HomeScreenRobot { // First Run elements fun verifyWelcomeHeader() = assertWelcomeHeader() - fun verifyGetTheMostHeader() = assertGetTheMostHeader() + fun verifyStartSyncHeader() = assertStartSyncHeader() fun verifyAccountsSignInButton() = assertAccountsSignInButton() fun verifyGetToKnowHeader() = assertGetToKnowHeader() fun verifyChooseThemeHeader() = assertChooseThemeHeader() @@ -83,14 +94,10 @@ class HomeScreenRobot { fun verifyDarkThemeDescription() = assertDarkThemeDescription() fun verifyAutomaticThemeToggle() = assertAutomaticThemeToggle() fun verifyAutomaticThemeDescription() = assertAutomaticThemeDescription() - fun verifyAutomaticPrivacyfHeader() = assertAutomaticPrivacyHeader() + fun verifyAutomaticPrivacyHeader() = assertAutomaticPrivacyHeader() fun verifyTrackingProtectionToggle() = assertTrackingProtectionToggle() fun verifyAutomaticPrivacyText() = assertAutomaticPrivacyText() - // What's new elements - fun verifyWhatsNewHeader() = assertWhatsNewHeather() - fun verifyWhatsNewLink() = assertWhatsNewLink() - // Browse privately fun verifyBrowsePrivatelyHeader() = assertBrowsePrivatelyHeader() fun verifyBrowsePrivatelyText() = assertBrowsePrivatelyText() @@ -445,6 +452,18 @@ class HomeScreenRobot { return BrowserRobot.Transition() } + fun renameTopSite(title: String, interact: HomeScreenRobot.() -> Unit): Transition { + onView(withText("Rename")) + .check((matches(withEffectiveVisibility(Visibility.VISIBLE)))) + .perform(click()) + onView(Matchers.allOf(withId(R.id.top_site_title), instanceOf(EditText::class.java))) + .perform(ViewActions.replaceText(title)) + onView(withId(android.R.id.button1)).perform((click())) + + HomeScreenRobot().interact() + return Transition() + } + fun removeTopSite(interact: HomeScreenRobot.() -> Unit): Transition { onView(withText("Remove")) .check((matches(withEffectiveVisibility(Visibility.VISIBLE)))) @@ -569,10 +588,10 @@ private fun verifySearchEngineIcon(searchEngineName: String) { // First Run elements private fun assertWelcomeHeader() = - onView(allOf(withText("Welcome to Firefox Preview!"))) + onView(allOf(withText("Welcome to ${appContext.appName}!"))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) -private fun assertGetTheMostHeader() = +private fun assertStartSyncHeader() = onView(allOf(withText("Start syncing bookmarks, passwords, and more with your Firefox account."))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) @@ -581,51 +600,69 @@ private fun assertAccountsSignInButton() = .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun assertGetToKnowHeader() = - onView(allOf(withText("Get to know Firefox Preview"))) + onView(allOf(withText("Get to know ${appContext.appName}"))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) -private fun assertChooseThemeHeader() = - onView(allOf(withText("Choose your theme"))) +private fun assertChooseThemeHeader() { + scrollToElementByText("Choose your theme") + onView(withText("Choose your theme")) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) - -private fun assertChooseThemeText() = +} +private fun assertChooseThemeText() { + scrollToElementByText("Choose your theme") onView(allOf(withText("Save some battery and your eyesight by enabling dark mode."))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +} -private fun assertLightThemeToggle() = +private fun assertLightThemeToggle() { + scrollToElementByText("Choose your theme") onView(ViewMatchers.withResourceName("theme_light_radio_button")) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +} -private fun assertLightThemeDescription() = +private fun assertLightThemeDescription() { + scrollToElementByText("Choose your theme") onView(allOf(withText("Light theme"))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +} -private fun assertDarkThemeToggle() = +private fun assertDarkThemeToggle() { + scrollToElementByText("Choose your theme") onView(ViewMatchers.withResourceName("theme_dark_radio_button")) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +} -private fun assertDarkThemeDescription() = +private fun assertDarkThemeDescription() { + scrollToElementByText("Choose your theme") onView(allOf(withText("Dark theme"))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) - -private fun assertAutomaticThemeToggle() = +} +private fun assertAutomaticThemeToggle() { + scrollToElementByText("Choose your theme") onView(withId(R.id.theme_automatic_radio_button)) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +} -private fun assertAutomaticThemeDescription() = +private fun assertAutomaticThemeDescription() { + scrollToElementByText("Choose your theme") onView(allOf(withText("Automatic"))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +} -private fun assertAutomaticPrivacyHeader() = +private fun assertAutomaticPrivacyHeader() { + scrollToElementByText("Automatic privacy") onView(allOf(withText("Automatic privacy"))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +} -private fun assertTrackingProtectionToggle() = onView( - allOf(ViewMatchers.withResourceName("tracking_protection_toggle")) -) - .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +private fun assertTrackingProtectionToggle() { + scrollToElementByText("Automatic privacy") + onView(withId(R.id.tracking_protection_toggle)) + .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +} private fun assertAutomaticPrivacyText() { + scrollToElementByText("Automatic privacy") onView( allOf( withText( @@ -636,60 +673,65 @@ private fun assertAutomaticPrivacyText() { .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) } -private fun assertBrowsePrivatelyHeader() = +private fun assertBrowsePrivatelyHeader() { + scrollToElementByText("Browse privately") onView(allOf(withText("Browse privately"))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +} -private fun assertBrowsePrivatelyText() = +private fun assertBrowsePrivatelyText() { + scrollToElementByText("Browse privately") onView(allOf(withText(containsString("Update your private browsing settings.")))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) - -private fun assertYourPrivacyHeader() = +} +private fun assertYourPrivacyHeader() { + scrollToElementByText("Your privacy") onView(allOf(withText("Your privacy"))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +} -private fun assertYourPrivacyText() = +private fun assertYourPrivacyText() { + scrollToElementByText("Your privacy") onView( allOf( withText( - "We’ve designed Firefox Preview to give you control over what you share online and what you share with us." + "We’ve designed ${appContext.appName} to give you control over what you share online and what you share with us." ) ) ) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +} -private fun assertPrivacyNoticeButton() = +private fun assertPrivacyNoticeButton() { + scrollToElementByText("Your privacy") onView(allOf(withText("Read our privacy notice"))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +} -// What's new elements -private fun assertWhatsNewHeather() = onView(allOf(withText("See what’s new"))) - .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) - -private fun assertWhatsNewLink() = onView(allOf(withText("Get answers here"))) - .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) - -private fun assertStartBrowsingButton() = +private fun assertStartBrowsingButton() { + scrollToElementByText("Start browsing") onView(allOf(withText("Start browsing"))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +} // Take a position -private fun assertTakePositionheader() = onView(allOf(withText("Take a position"))) - .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +private fun assertTakePositionheader() { + scrollToElementByText("Take a position") + onView(allOf(withText("Take a position"))) + .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +} -private fun assertTakePositionTopRadioButton() = +private fun assertTakePositionTopRadioButton() { + scrollToElementByText("Take a position") onView(ViewMatchers.withResourceName("toolbar_top_radio_button")) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +} -private fun assertTakePositionBottomRadioButton() = +private fun assertTakePositionBottomRadioButton() { + scrollToElementByText("Take a position") onView(ViewMatchers.withResourceName("toolbar_bottom_radio_button")) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) - -const val PRIVATE_SESSION_MESSAGE = - "Firefox Preview clears your search and browsing history from private tabs when you close them" + - " or quit the app. While this doesn’t make you anonymous to websites or your internet" + - " service provider, it makes it easier to keep what you do online private from anyone" + - " else who uses this device." +} private fun assertPrivateSessionMessage() = onView(withId(R.id.private_session_description)) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SearchRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SearchRobot.kt index 85f67ec7f..22be73813 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SearchRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SearchRobot.kt @@ -126,7 +126,7 @@ class SearchRobot { val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) private lateinit var sessionLoadedIdlingResource: SessionLoadedIdlingResource - fun dismiss(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition { + fun dismissSearchBar(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition { mDevice.waitForIdle() mDevice.pressBack() HomeScreenRobot().interact() diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsRobot.kt index 9e95e31e3..e83a759f5 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsRobot.kt @@ -20,6 +20,7 @@ import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers.Visibility import androidx.test.espresso.matcher.ViewMatchers.hasDescendant import androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withText @@ -425,15 +426,17 @@ private fun assertAboutHeading(): ViewInteraction { } private fun assertRateOnGooglePlay(): ViewInteraction { - scrollToElementByText("About Firefox Preview") + onView(withId(R.id.recycler_view)) + .perform(RecyclerViewActions.scrollTo(hasDescendant(withText("Rate on Google Play")))) return onView(withText("Rate on Google Play")) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) } private fun assertAboutFirefoxPreview(): ViewInteraction { - scrollToElementByText("About Firefox Preview") + onView(withId(R.id.recycler_view)) + .perform(RecyclerViewActions.scrollTo(hasDescendant(withText("About Firefox Preview")))) return onView(withText("About Firefox Preview")) - .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) + .check(matches(isDisplayed())) } fun swipeToBottom() = onView(withId(R.id.recycler_view)).perform(ViewActions.swipeUp()) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SyncedTabsRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SyncedTabsRobot.kt index facf6ebb0..9add0cd59 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SyncedTabsRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SyncedTabsRobot.kt @@ -8,7 +8,6 @@ import androidx.test.espresso.Espresso.onView import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.matcher.ViewMatchers.withContentDescription import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility -import androidx.test.espresso.matcher.ViewMatchers.withResourceName import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.espresso.matcher.ViewMatchers.Visibility import androidx.test.platform.app.InstrumentationRegistry @@ -22,9 +21,7 @@ import org.mozilla.fenix.helpers.click */ class SyncedTabsRobot { - fun verifyNavigationToolBarHeader() = assertNavigationToolBarHeader() - - fun verifySyncedTabsStatus() = assertSyncedTabsStatus() + fun verifySyncedTabsMenuHeader() = assertSyncedTabsMenuHeader() class Transition { val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())!! @@ -41,12 +38,7 @@ class SyncedTabsRobot { private fun goBackButton() = onView(allOf(withContentDescription("Navigate up"))) -private fun assertNavigationToolBarHeader() { +private fun assertSyncedTabsMenuHeader() { onView(withText(R.string.synced_tabs)) .check((matches(withEffectiveVisibility(Visibility.VISIBLE)))) } - -private fun assertSyncedTabsStatus() { - onView(withResourceName("sync_tabs_status")) - .check((matches(withEffectiveVisibility(Visibility.VISIBLE)))) -} diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt index d13772c9c..a14b0e539 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt @@ -7,13 +7,17 @@ package org.mozilla.fenix.ui.robots import android.content.Context +import android.view.View import androidx.recyclerview.widget.RecyclerView import androidx.test.core.app.ApplicationProvider import androidx.test.espresso.Espresso import androidx.test.espresso.Espresso.onView import androidx.test.espresso.NoMatchingViewException +import androidx.test.espresso.UiController +import androidx.test.espresso.ViewAction import androidx.test.espresso.action.ViewActions import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.assertion.ViewAssertions.doesNotExist import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.contrib.RecyclerViewActions import androidx.test.espresso.matcher.ViewMatchers @@ -28,14 +32,19 @@ import androidx.test.uiautomator.By.text import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.Until import androidx.test.uiautomator.Until.findObject +import com.google.android.material.bottomsheet.BottomSheetBehavior import org.hamcrest.CoreMatchers.allOf import org.hamcrest.CoreMatchers.anyOf import org.hamcrest.CoreMatchers.containsString +import org.hamcrest.Matcher import org.mozilla.fenix.R import org.mozilla.fenix.helpers.TestAssetHelper import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime import org.mozilla.fenix.helpers.click import org.mozilla.fenix.helpers.ext.waitNotNull +import org.mozilla.fenix.helpers.idlingresource.BottomSheetBehaviorStateIdlingResource +import org.mozilla.fenix.helpers.matchers.BottomSheetBehaviorHalfExpandedMaxRatioMatcher +import org.mozilla.fenix.helpers.matchers.BottomSheetBehaviorStateMatcher /** * Implementation of Robot Pattern for the home screen menu. @@ -52,6 +61,10 @@ class TabDrawerRobot { fun verifyNewTabButton() = assertNewTabButton() fun verifyTabTrayOverflowMenu(visibility: Boolean) = assertTabTrayOverflowButton(visibility) + fun verifyTabTrayIsClosed() = assertTabTrayDoesNotExist() + fun verifyHalfExpandedRatio() = assertMinisculeHalfExpandedRatio() + fun verifyBehaviorState(expectedState: Int) = assertBehaviorState(expectedState) + fun closeTab() { closeTabButton().click() } @@ -126,9 +139,7 @@ class TabDrawerRobot { fun closeTabDrawer(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition { mDevice.waitForIdle(waitingTime) - // Dismisses the tab tray bottom sheet with 2 handle clicks onView(withId(R.id.handle)).perform( - click(), click() ) BrowserRobot().interact() @@ -169,6 +180,52 @@ class TabDrawerRobot { BrowserRobot().interact() return BrowserRobot.Transition() } + + fun clickTopBar(interact: TabDrawerRobot.() -> Unit): Transition { + onView(withId(R.id.topBar)).click() + TabDrawerRobot().interact() + return Transition() + } + + fun advanceToHalfExpandedState(interact: TabDrawerRobot.() -> Unit): Transition { + onView(withId(R.id.tab_wrapper)).perform(object : ViewAction { + override fun getDescription(): String { + return "Advance a BottomSheetBehavior to STATE_HALF_EXPANDED" + } + + override fun getConstraints(): Matcher { + return ViewMatchers.isAssignableFrom(View::class.java) + } + + override fun perform(uiController: UiController?, view: View?) { + val behavior = BottomSheetBehavior.from(view!!) + behavior.state = BottomSheetBehavior.STATE_HALF_EXPANDED + } + }) + TabDrawerRobot().interact() + return Transition() + } + + fun waitForTabTrayBehaviorToIdle(interact: TabDrawerRobot.() -> Unit): Transition { + var behavior: BottomSheetBehavior<*>? = null + onView(withId(R.id.tab_wrapper)).perform(object : ViewAction { + override fun getDescription(): String { + return "Postpone actions to after the BottomSheetBehavior has settled" + } + + override fun getConstraints(): Matcher { + return ViewMatchers.isAssignableFrom(View::class.java) + } + + override fun perform(uiController: UiController?, view: View?) { + behavior = BottomSheetBehavior.from(view!!) + } + }) + runWithIdleRes(BottomSheetBehaviorStateIdlingResource(behavior!!)) { + TabDrawerRobot().interact() + } + return Transition() + } } } @@ -239,6 +296,21 @@ private fun assertTabTrayOverflowButton(visible: Boolean) = onView(withId(R.id.tab_tray_overflow)) .check(matches(withEffectiveVisibility(visibleOrGone(visible)))) +private fun assertTabTrayDoesNotExist() { + onView(withId(R.id.tab_wrapper)) + .check(doesNotExist()) +} + +private fun assertMinisculeHalfExpandedRatio() { + onView(withId(R.id.tab_wrapper)) + .check(matches(BottomSheetBehaviorHalfExpandedMaxRatioMatcher(0.001f))) +} + +private fun assertBehaviorState(expectedState: Int) { + onView(withId(R.id.tab_wrapper)) + .check(matches(BottomSheetBehaviorStateMatcher(expectedState))) +} + private fun tab(title: String) = onView( allOf( diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/ThreeDotMenuMainRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/ThreeDotMenuMainRobot.kt index e28cd8ef9..03e6ec5bf 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/ThreeDotMenuMainRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/ThreeDotMenuMainRobot.kt @@ -15,6 +15,7 @@ import androidx.test.espresso.ViewAction import androidx.test.espresso.action.ViewActions import androidx.test.espresso.action.ViewActions.click import androidx.test.espresso.action.ViewActions.swipeDown +import androidx.test.espresso.action.ViewActions.swipeUp import androidx.test.espresso.assertion.ViewAssertions import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.contrib.RecyclerViewActions @@ -68,6 +69,7 @@ class ThreeDotMenuMainRobot { fun verifyShareTabButton() = assertShareTabButton() fun verifySaveCollection() = assertSaveCollectionButton() + fun verifySelectTabs() = assertSelectTabsButton() fun clickBrowserViewSaveCollectionButton() { browserViewSaveCollectionButton().click() @@ -114,9 +116,11 @@ class ThreeDotMenuMainRobot { fun verifyAddToMobileHome() = assertAddToMobileHome() fun verifyDesktopSite() = assertDesktopSite() fun verifyOpenInAppButton() = assertOpenInAppButton() + fun verifyDownloadsButton() = assertDownloadsButton() fun verifyThreeDotMainMenuItems() { verifyAddOnsButton() + verifyDownloadsButton() verifyHistoryButton() verifyBookmarksButton() verifySyncedTabsButton() @@ -125,6 +129,7 @@ class ThreeDotMenuMainRobot { verifyAddFirefoxHome() verifyAddToMobileHome() verifyDesktopSite() + verifySaveCollection() verifyAddBookmarkButton() verifyShareButton() verifyForwardButton() @@ -135,14 +140,6 @@ class ThreeDotMenuMainRobot { private val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) - fun clickAddOnsReportSiteIssue(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition { - addOnsButton().click() - addOnsReportSiteIssueButton().click() - - BrowserRobot().interact() - return BrowserRobot.Transition() - } - fun openSettings(interact: SettingsRobot.() -> Unit): SettingsRobot.Transition { onView(withId(R.id.mozac_browser_menu_recyclerView)).perform(ViewActions.swipeDown()) onView(allOf(withResourceName("text"), withText(R.string.browser_menu_settings))) @@ -224,13 +221,6 @@ class ThreeDotMenuMainRobot { return BrowserRobot.Transition() } - fun goBackToBrowser(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition { - mDevice.pressBack() - - BrowserRobot().interact() - return BrowserRobot.Transition() - } - fun close(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition { // Close three dot mDevice.pressBack() @@ -359,6 +349,13 @@ class ThreeDotMenuMainRobot { SettingsSubMenuAddonsManagerRobot().interact() return SettingsSubMenuAddonsManagerRobot.Transition() } + + fun exitSaveCollection(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition { + exitSaveCollectionButton().click() + + BrowserRobot().interact() + return BrowserRobot.Transition() + } } } @@ -372,9 +369,10 @@ private fun assertSettingsButton() = settingsButton() .check(matches(isCompletelyDisplayed())) private fun addOnsButton() = onView(allOf(withText("Add-ons"))) -private fun assertAddOnsButton() = addOnsButton() - .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) -private fun addOnsReportSiteIssueButton() = onView(allOf(withText("Report Site Issue…"))) +private fun assertAddOnsButton() { + onView(withId(R.id.mozac_browser_menu_menuView)).perform(swipeDown()) + addOnsButton().check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +} private fun historyButton() = onView(allOf(withText(R.string.library_history))) private fun assertHistoryButton() = historyButton() @@ -397,8 +395,10 @@ private fun assertForwardButton() = forwardButton() .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun addBookmarkButton() = onView(ViewMatchers.withContentDescription("Bookmark")) -private fun assertAddBookmarkButton() = addBookmarkButton() - .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +private fun assertAddBookmarkButton() { + onView(withId(R.id.mozac_browser_menu_menuView)).perform(swipeUp()) + addBookmarkButton().check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +} private fun editBookmarkButton() = onView(ViewMatchers.withContentDescription("Edit bookmark")) private fun assertEditBookmarkButton() = editBookmarkButton() @@ -431,6 +431,10 @@ private fun saveCollectionButton() = onView(allOf(withText("Save to collection") private fun assertSaveCollectionButton() = saveCollectionButton() .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +private fun selectTabsButton() = onView(allOf(withText("Select tabs"))).inRoot(RootMatchers.isPlatformPopup()) +private fun assertSelectTabsButton() = selectTabsButton() + .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) + private fun addNewCollectionButton() = onView(allOf(withText("Add new collection"))) private fun assertaddNewCollectionButton() = addNewCollectionButton() .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) @@ -454,10 +458,10 @@ private fun SendToDeviceTitle() = private fun assertSendToDeviceTitle() = SendToDeviceTitle() .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) -private fun ShareALinkTitle() = +private fun shareALinkTitle() = onView(allOf(withText("ALL ACTIONS"), withResourceName("apps_link_header"))) -private fun assertShareALinkTitle() = ShareALinkTitle() +private fun assertShareALinkTitle() = shareALinkTitle() private fun whatsNewButton() = onView( allOf( @@ -511,12 +515,8 @@ private fun assertAddToMobileHome() { private fun desktopSiteButton() = onView(allOf(withText(R.string.browser_menu_desktop_site))) private fun assertDesktopSite() { - onView(withId(R.id.mozac_browser_menu_recyclerView)) - .perform( - RecyclerViewActions.scrollTo( - hasDescendant(withText(R.string.browser_menu_desktop_site)) - ) - ).check(matches(withEffectiveVisibility(Visibility.VISIBLE))) + onView(withId(R.id.mozac_browser_menu_menuView)).perform(swipeUp()) + desktopSiteButton().check(matches(isDisplayed())) } private fun openInAppButton() = @@ -530,9 +530,15 @@ private fun assertOpenInAppButton() { ).check(matches(withEffectiveVisibility(Visibility.VISIBLE))) } -private fun addonsManagerButton() = onView(withText("Add-ons Manager")) +private fun downloadsButton() = onView(withText(R.string.library_downloads)) +private fun assertDownloadsButton() { + onView(withId(R.id.mozac_browser_menu_menuView)).perform(swipeDown()) + downloadsButton().check(matches(isDisplayed())) +} private fun clickAddonsManagerButton() { onView(withId(R.id.mozac_browser_menu_menuView)).perform(swipeDown()) - onView(withText("Add-ons")).check(matches(isCompletelyDisplayed())).click() + addOnsButton().check(matches(isCompletelyDisplayed())).click() } + +private fun exitSaveCollectionButton() = onView(withId(R.id.back_button)).check(matches(isDisplayed())) diff --git a/app/src/geckoBeta/java/org/mozilla/fenix/engine/GeckoProvider.kt b/app/src/geckoBeta/java/org/mozilla/fenix/engine/GeckoProvider.kt index eb13a10e4..2c58b165a 100644 --- a/app/src/geckoBeta/java/org/mozilla/fenix/engine/GeckoProvider.kt +++ b/app/src/geckoBeta/java/org/mozilla/fenix/engine/GeckoProvider.kt @@ -12,11 +12,17 @@ import mozilla.components.lib.crash.handler.CrashHandlerService import mozilla.components.service.sync.logins.GeckoLoginStorageDelegate import org.mozilla.fenix.Config import org.mozilla.fenix.ext.components +import org.mozilla.geckoview.ContentBlocking import org.mozilla.geckoview.GeckoRuntime import org.mozilla.geckoview.GeckoRuntimeSettings +import org.mozilla.geckoview.ContentBlocking.SafeBrowsingProvider object GeckoProvider { private var runtime: GeckoRuntime? = null + const val CN_UPDATE_URL = + "https://sb.firefox.com.cn/downloads?client=SAFEBROWSING_ID&appver=%MAJOR_VERSION%&pver=2.2" + const val CN_GET_HASH_URL = + "https://sb.firefox.com.cn/gethash?client=SAFEBROWSING_ID&appver=%MAJOR_VERSION%&pver=2.2" @Synchronized fun getOrCreateRuntime( @@ -53,6 +59,28 @@ object GeckoProvider { runtimeSettings.fontSizeFactor = fontSize } + // Add safebrowsing providers for China + if (Config.channel.isMozillaOnline) { + val mozcn = SafeBrowsingProvider + .withName("mozcn") + .version("2.2") + .lists("m6eb-phish-shavar", "m6ib-phish-shavar") + .updateUrl(CN_UPDATE_URL) + .getHashUrl(CN_GET_HASH_URL) + .build() + + runtimeSettings.contentBlocking.setSafeBrowsingProviders(mozcn, + // Keep the existing configuration + ContentBlocking.GOOGLE_SAFE_BROWSING_PROVIDER, + ContentBlocking.GOOGLE_LEGACY_SAFE_BROWSING_PROVIDER) + + runtimeSettings.contentBlocking.setSafeBrowsingPhishingTable( + "m6eb-phish-shavar", + "m6ib-phish-shavar", + // Existing configuration + "goog-phish-proto") + } + val geckoRuntime = GeckoRuntime.create(context, runtimeSettings) val loginStorageDelegate = GeckoLoginStorageDelegate(storage) geckoRuntime.loginStorageDelegate = GeckoLoginDelegateWrapper(loginStorageDelegate) diff --git a/app/src/geckoNightly/java/org/mozilla/fenix/engine/GeckoProvider.kt b/app/src/geckoNightly/java/org/mozilla/fenix/engine/GeckoProvider.kt index 031c1c6c1..38c751f30 100644 --- a/app/src/geckoNightly/java/org/mozilla/fenix/engine/GeckoProvider.kt +++ b/app/src/geckoNightly/java/org/mozilla/fenix/engine/GeckoProvider.kt @@ -14,9 +14,15 @@ import org.mozilla.fenix.Config import org.mozilla.fenix.ext.components import org.mozilla.geckoview.GeckoRuntime import org.mozilla.geckoview.GeckoRuntimeSettings +import org.mozilla.geckoview.ContentBlocking +import org.mozilla.geckoview.ContentBlocking.SafeBrowsingProvider object GeckoProvider { private var runtime: GeckoRuntime? = null + const val CN_UPDATE_URL = + "https://sb.firefox.com.cn/downloads?client=SAFEBROWSING_ID&appver=%MAJOR_VERSION%&pver=2.2" + const val CN_GET_HASH_URL = + "https://sb.firefox.com.cn/gethash?client=SAFEBROWSING_ID&appver=%MAJOR_VERSION%&pver=2.2" @Synchronized fun getOrCreateRuntime( @@ -53,6 +59,28 @@ object GeckoProvider { runtimeSettings.fontSizeFactor = fontSize } + // Add safebrowsing providers for China + if (Config.channel.isMozillaOnline) { + val mozcn = SafeBrowsingProvider + .withName("mozcn") + .version("2.2") + .lists("m6eb-phish-shavar", "m6ib-phish-shavar") + .updateUrl(CN_UPDATE_URL) + .getHashUrl(CN_GET_HASH_URL) + .build() + + runtimeSettings.contentBlocking.setSafeBrowsingProviders(mozcn, + // Keep the existing configuration + ContentBlocking.GOOGLE_SAFE_BROWSING_PROVIDER, + ContentBlocking.GOOGLE_LEGACY_SAFE_BROWSING_PROVIDER) + + runtimeSettings.contentBlocking.setSafeBrowsingPhishingTable( + "m6eb-phish-shavar", + "m6ib-phish-shavar", + // Existing configuration + "goog-phish-proto") + } + val geckoRuntime = GeckoRuntime.create(context, runtimeSettings) val loginStorageDelegate = GeckoLoginStorageDelegate(storage) geckoRuntime.loginStorageDelegate = GeckoLoginDelegateWrapper(loginStorageDelegate) diff --git a/app/src/main/assets/high_risk_error_pages.html b/app/src/main/assets/high_risk_error_pages.html index d0f04841d..c74469ca7 100644 --- a/app/src/main/assets/high_risk_error_pages.html +++ b/app/src/main/assets/high_risk_error_pages.html @@ -34,4 +34,9 @@ + diff --git a/app/src/main/assets/low_and_medium_risk_error_pages.html b/app/src/main/assets/low_and_medium_risk_error_pages.html index e930454df..baa08deff 100644 --- a/app/src/main/assets/low_and_medium_risk_error_pages.html +++ b/app/src/main/assets/low_and_medium_risk_error_pages.html @@ -71,6 +71,10 @@