├── .cron.yml ├── .editorconfig ├── .github ├── ISSUE_TEMPLATE │ ├── bug-report.md │ ├── ui-test.md │ └── user-story.md ├── pull_request_template.md └── workflows │ └── glean-probe-scraper.yml ├── .gitignore ├── .mergify.yml ├── .taskcluster.yml ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── lint-baseline.xml ├── lint.xml ├── metrics.yaml ├── proguard-rules.pro └── src │ ├── androidTest │ ├── assets │ │ ├── pages │ │ │ ├── audioMediaPage.html │ │ │ ├── basic_nav_uuid.html │ │ │ ├── dom_element_focus_test.html │ │ │ ├── download.html │ │ │ ├── generic1.html │ │ │ ├── generic2.html │ │ │ ├── generic3.html │ │ │ ├── generic4.html │ │ │ ├── jquery-1.10.2.js │ │ │ ├── lorem-ipsum.html │ │ │ ├── noControlsVideoMediaPage.html │ │ │ ├── refresh.html │ │ │ └── videoMediaPage.html │ │ └── resources │ │ │ ├── audioSample.mp3 │ │ │ ├── mov_bbb.mp4 │ │ │ ├── rabbit.jpg │ │ │ └── web_icon.png │ └── java │ │ └── org │ │ └── mozilla │ │ └── reference │ │ └── browser │ │ ├── FirefoxTestApplication.kt │ │ ├── FirefoxTestRunner.kt │ │ ├── ext │ │ ├── UiDevice.kt │ │ └── ViewGroup.kt │ │ ├── helpers │ │ ├── Assert.kt │ │ ├── BrowserActivityTestRule.kt │ │ ├── Constants.kt │ │ ├── Matchers.kt │ │ ├── MockWebServer.kt │ │ ├── RetryTestRule.kt │ │ ├── SessionLoadedIdlingResource.kt │ │ ├── TestAssetHelper.kt │ │ ├── TestHelper.kt │ │ ├── ext │ │ │ ├── String.kt │ │ │ └── ViewInteraction.kt │ │ └── matchers │ │ │ └── TabMatcher.kt │ │ └── ui │ │ ├── AddonsTest.kt │ │ ├── ContextMenusTest.kt │ │ ├── CustomTabsTest.kt │ │ ├── DownloadTest.kt │ │ ├── MediaPlaybackTest.kt │ │ ├── ReaderViewTest.kt │ │ ├── SearchTest.kt │ │ ├── SettingsViewTest.kt │ │ ├── TabTrayMenuTest.kt │ │ ├── ThreeDotMenuTest.kt │ │ └── robots │ │ ├── AddToHomeScreenRobot.kt │ │ ├── AddonsManagerRobot.kt │ │ ├── AwesomeBarRobot.kt │ │ ├── BrowserRobot.kt │ │ ├── ContentPanelRobot.kt │ │ ├── CustomTabRobot.kt │ │ ├── DownloadRobot.kt │ │ ├── ExternalAppsRobot.kt │ │ ├── FindInPagePanelRobot.kt │ │ ├── NavigationToolbarRobot.kt │ │ ├── NotificationRobot.kt │ │ ├── ReaderViewRobot.kt │ │ ├── SettingsViewPrivacyRobot.kt │ │ ├── SettingsViewRobot.kt │ │ ├── SyncedTabsRobot.kt │ │ ├── TabTrayMenuRobot.kt │ │ ├── TabTrayMoreOptionsMenuRobot.kt │ │ └── ThreeDotMenuRobot.kt │ ├── debug │ └── res │ │ ├── mipmap-hdpi │ │ ├── ic_icon_background.png │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_icon_background.png │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_icon_background.png │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_icon_background.png │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_icon_background.png │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ └── firebase.xml │ └── main │ ├── AndroidManifest.xml │ ├── java │ ├── mozilla │ │ └── components │ │ │ ├── compose │ │ │ └── browser │ │ │ │ └── toolbar │ │ │ │ └── BrowserToolbar.kt │ │ │ └── lib │ │ │ └── state │ │ │ └── Store.kt │ └── org │ │ └── mozilla │ │ └── reference │ │ └── browser │ │ ├── AppRequestInterceptor.kt │ │ ├── BrowserActivity.kt │ │ ├── BrowserApplication.kt │ │ ├── BrowserTestActivity.kt │ │ ├── Components.kt │ │ ├── CrashListActivity.kt │ │ ├── EngineProvider.kt │ │ ├── ExternalAppBrowserActivity.kt │ │ ├── IntentReceiverActivity.kt │ │ ├── IntentRequestCodes.kt │ │ ├── NotificationManager.kt │ │ ├── addons │ │ ├── AddonDetailsActivity.kt │ │ ├── AddonSettingsActivity.kt │ │ ├── AddonsActivity.kt │ │ ├── AddonsFragment.kt │ │ ├── Extensions.kt │ │ ├── InstalledAddonDetailsActivity.kt │ │ ├── PermissionsDetailsActivity.kt │ │ ├── WebExtensionActionPopupActivity.kt │ │ └── WebExtensionPromptFeature.kt │ │ ├── autofill │ │ ├── AutofillConfirmActivity.kt │ │ ├── AutofillPreference.kt │ │ ├── AutofillSearchActivity.kt │ │ ├── AutofillService.kt │ │ └── AutofillUnlockActivity.kt │ │ ├── browser │ │ ├── BaseBrowserFragment.kt │ │ ├── BrowserFragment.kt │ │ ├── ContextMenuIntegration.kt │ │ ├── CrashIntegration.kt │ │ ├── CustomTabsIntegration.kt │ │ ├── ExternalAppBrowserFragment.kt │ │ ├── FindInPageIntegration.kt │ │ ├── ReaderViewIntegration.kt │ │ └── ToolbarIntegration.kt │ │ ├── components │ │ ├── Analytics.kt │ │ ├── BackgroundServices.kt │ │ ├── Core.kt │ │ ├── Push.kt │ │ ├── Services.kt │ │ ├── UseCases.kt │ │ └── Utilities.kt │ │ ├── compose │ │ └── ComposableComponents.kt │ │ ├── customtabs │ │ └── CustomTabsService.kt │ │ ├── downloads │ │ └── DownloadService.kt │ │ ├── ext │ │ ├── Context.kt │ │ ├── Fragment.kt │ │ ├── Long.kt │ │ └── String.kt │ │ ├── media │ │ └── MediaSessionService.kt │ │ ├── pip │ │ └── PictureInPictureIntegration.kt │ │ ├── push │ │ ├── FirebasePush.kt │ │ ├── PushFxaIntegration.kt │ │ └── WebPushEngineIntegration.kt │ │ ├── search │ │ └── AwesomeBarWrapper.kt │ │ ├── settings │ │ ├── AboutFragment.kt │ │ ├── AccountSettingsFragment.kt │ │ ├── PairSettingsFragment.kt │ │ ├── PrivacySettingsFragment.kt │ │ ├── Settings.kt │ │ ├── SettingsActivity.kt │ │ └── SettingsFragment.kt │ │ ├── sync │ │ └── BrowserFxAEntryPoint.kt │ │ └── tabs │ │ ├── LastTabFeature.kt │ │ ├── PrivatePage.kt │ │ ├── TabsPanel.kt │ │ ├── TabsToolbar.kt │ │ ├── TabsTouchHelper.kt │ │ ├── TabsTrayFragment.kt │ │ └── synced │ │ ├── SyncedTabsActivity.kt │ │ ├── SyncedTabsAdapter.kt │ │ ├── SyncedTabsFragment.kt │ │ ├── SyncedTabsIntegration.kt │ │ ├── SyncedTabsLayout.kt │ │ └── SyncedTabsViewHolder.kt │ └── res │ ├── drawable-hdpi │ └── ic_notification.png │ ├── drawable-mdpi │ └── ic_notification.png │ ├── drawable-xhdpi │ └── ic_notification.png │ ├── drawable-xxhdpi │ └── ic_notification.png │ ├── drawable-xxxhdpi │ └── ic_notification.png │ ├── drawable │ ├── addon_textview_selector.xml │ ├── ic_icon_foreground.xml │ ├── mozac_ic_extensions_black.xml │ ├── mozac_ic_permissions.xml │ └── url_background.xml │ ├── layout │ ├── activity_add_on_details.xml │ ├── activity_add_on_permissions.xml │ ├── activity_add_on_settings.xml │ ├── activity_installed_add_on_details.xml │ ├── activity_main.xml │ ├── add_ons_permission_item.xml │ ├── amo_collection_override_dialog.xml │ ├── browser_tabstray_item.xml │ ├── fragment_about.xml │ ├── fragment_add_on_settings.xml │ ├── fragment_add_ons.xml │ ├── fragment_browser.xml │ ├── fragment_pairing.xml │ ├── fragment_synced_tabs.xml │ ├── fragment_tabstray.xml │ ├── layout_synced_tabs.xml │ ├── overlay_add_on_progress.xml │ ├── preference_autofill.xml │ ├── view_synced_tabs_group.xml │ └── view_synced_tabs_item.xml │ ├── menu │ └── tabstray_menu.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_icon_background.png │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_icon_background.png │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_icon_background.png │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_icon_background.png │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_icon_background.png │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── raw │ ├── private_mode.html │ └── private_style.css │ ├── values │ ├── attrs.xml │ ├── colors.xml │ ├── dimens.xml │ ├── preference_keys.xml │ ├── strings.xml │ └── style.xml │ └── xml │ ├── account_preferences.xml │ ├── backup_rules.xml │ ├── data_extraction_rules.xml │ ├── preferences.xml │ └── privacy_preferences.xml ├── automation ├── gradle │ └── versionCode.gradle └── taskcluster │ ├── androidTest │ ├── flank-arm64-v8a.yml │ ├── flank-x86.yml │ └── ui-test.sh │ └── update_android_components.sh ├── build.gradle ├── buildSrc ├── build.gradle.kts └── src │ └── main │ └── java │ └── Config.kt ├── certificates ├── nightly.pem └── raptor.pem ├── config ├── detekt-baseline.xml ├── detekt.yml └── license.template ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── l10n.toml ├── settings.gradle └── taskcluster ├── config.yml ├── docker ├── REGISTRY ├── android-build │ └── Dockerfile ├── base │ └── Dockerfile ├── bump │ ├── Dockerfile │ ├── mozilla_key.asc │ └── owner_trust.db └── ui-tests │ └── Dockerfile ├── kinds ├── build-bundle │ └── kind.yml ├── build │ └── kind.yml ├── bump │ └── kind.yml ├── docker-image │ └── kind.yml ├── fetch │ └── kind.yml ├── geckoview │ └── kind.yml ├── lint │ └── kind.yml ├── pr │ └── kind.yml ├── push-bundle │ └── kind.yml ├── raptor │ └── kind.yml ├── signing-bundle │ └── kind.yml ├── signing │ └── kind.yml ├── test │ └── kind.yml └── toolchain │ ├── android.yml │ ├── kind.yml │ └── minidump-stackwalk.yml ├── rb_taskgraph ├── __init__.py ├── gradle.py ├── job.py ├── loader │ ├── __init__.py │ └── single_dep.py ├── routes.py ├── target_tasks.py ├── transforms │ ├── __init__.py │ ├── build_aab.py │ ├── build_apk.py │ ├── notify.py │ ├── push_android_app.py │ ├── raptor.py │ ├── secrets.py │ ├── signing.py │ ├── signing_apks.py │ ├── signing_bundle.py │ └── variant.py └── worker_types.py ├── requirements.in ├── requirements.txt └── scripts ├── get-secret.py ├── toolchain ├── android-gradle-dependencies.sh ├── android-gradle-dependencies │ ├── after.sh │ ├── before.sh │ └── nexus.xml └── repack-android-sdk-linux.sh └── write-dummy-secret.py /.cron.yml: -------------------------------------------------------------------------------- 1 | # Definitions for jobs that run periodically. For details on the format, see 2 | # `taskcluster/taskgraph/cron/schema.py`. For documentation, see 3 | # `taskcluster/docs/cron.rst`. 4 | --- 5 | 6 | jobs: 7 | - name: nightly 8 | job: 9 | type: decision-task 10 | treeherder-symbol: Nd 11 | target-tasks-method: nightly 12 | when: 13 | - {hour: 9, minute: 0} 14 | # Cannot name the following entry "bump-android-component" because the full hookId is larger 15 | # than 64 characters. For more details see: https://phabricator.services.mozilla.com/D67443 16 | - name: bump-android-comp 17 | job: 18 | type: decision-task 19 | treeherder-symbol: bump-ac 20 | target-tasks-method: bump_android_components 21 | when: 22 | - {hour: 4, minute: 0} 23 | - {hour: 10, minute: 0} 24 | - {hour: 16, minute: 0} 25 | - {hour: 22, minute: 0} 26 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{kt,kts}] 2 | ij_kotlin_allow_trailing_comma_on_call_site=true 3 | ij_kotlin_allow_trailing_comma=true 4 | 5 | [*] 6 | insert_final_newline = true 7 | max_line_length = 120 # same as detekt.yml 8 | 9 | # rules we should look into enabling 10 | ktlint_standard_function-naming = disabled 11 | ktlint_standard_indent = disabled 12 | ktlint_standard_multiline-expression-wrapping = disabled 13 | ktlint_standard_string-template-indent = disabled 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41E Bug report" 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: "\U0001F41E bug" 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Steps to reproduce 11 | 1. 12 | 13 | ### Expected behavior 14 | - 15 | 16 | ### Actual behavior 17 | - 18 | 19 | ### Device information 20 | 21 | * Android device: ? 22 | * Reference Browser version: ? 23 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/ui-test.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "💔 Intermittent UI Test Issue" 3 | about: Create an issue to help log a UI test failure 4 | labels: "eng:ui-test, intermittent-test" 5 | title: "Intermittent UI test failure - " 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Firebase Test Run: 11 | Provide a Firebase test run report link here showcasing the problem 12 | ### Stacktrace: 13 | ### Build: 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/user-story.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F31F User Story" 3 | about: Create a user story to satisfy a feature request. 4 | title: '' 5 | labels: "\U0001F31F feature" 6 | assignees: '' 7 | 8 | --- 9 | 10 | 14 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Pull Request checklist 4 | 5 | - [ ] **Accessibility**: The code in this PR follows [accessibility best practices](https://github.com/mozilla-mobile/shared-docs/blob/master/android/accessibility_guide.md) or does not include any user facing features 6 | -------------------------------------------------------------------------------- /.github/workflows/glean-probe-scraper.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Glean probe-scraper 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | branches: [master] 8 | jobs: 9 | glean-probe-scraper: 10 | uses: mozilla/probe-scraper/.github/workflows/glean.yaml@main 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | build/ 19 | !taskcluster/ci/build 20 | 21 | # Local configuration file (sdk path, etc) 22 | local.properties 23 | 24 | # Proguard folder generated by Eclipse 25 | proguard/ 26 | 27 | # Log Files 28 | *.log 29 | 30 | # Android Studio Navigation editor temp files 31 | .navigation/ 32 | 33 | # Android Studio captures folder 34 | captures/ 35 | 36 | # Intellij 37 | *.iml 38 | .idea/ 39 | 40 | # Vim swap files 41 | *.sw[op] 42 | 43 | # Keystore files 44 | *.jks 45 | 46 | # Local checkout of localization files 47 | l10n-repo/ 48 | 49 | # Compiled python code 50 | *.pyc 51 | 52 | # OS X 53 | .DS_Store 54 | 55 | # jacoco.exec 56 | jacoco.exec 57 | 58 | # Sentry token file 59 | .sentry_token 60 | 61 | # UI test artifacts 62 | .firebase_token* 63 | results/ 64 | test_artifacts/ 65 | google-cloud-sdk/ 66 | *.jar 67 | *.gz 68 | -------------------------------------------------------------------------------- /.mergify.yml: -------------------------------------------------------------------------------- 1 | queue_rules: 2 | - name: default 3 | conditions: 4 | - status-success=pr-complete 5 | merge_method: rebase 6 | pull_request_rules: 7 | - name: MickeyMoz - Auto Merge 8 | conditions: 9 | - author=MickeyMoz 10 | - status-success=pr-complete 11 | - files=gradle/libs.versions.toml 12 | actions: 13 | review: 14 | type: APPROVE 15 | message: MickeyMoz 💪 16 | queue: 17 | name: default 18 | - name: Needs landing - Merge 19 | conditions: 20 | - status-success=pr-complete 21 | - label=needs landing 22 | - "#approved-reviews-by>=1" 23 | actions: 24 | queue: 25 | name: default 26 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | # This CODEOWNERS file defines individuals or teams that are responsible 6 | # for code in this repository. Code owners are automatically requested 7 | # for review when someone opens a pull request that modifies code that 8 | # they own. Order is important; the last matching pattern takes the most 9 | # precedence. 10 | # A CODEOWNERS file uses a pattern that follows the same rules used in 11 | # gitignore files. The pattern is followed by one or more GitHub usernames 12 | # or team names using the standard @username or @org/team-name format. 13 | # You can also refer to a user by an email address that has been added 14 | # to their GitHub account, for example user@example.com. 15 | # https://help.github.com/articles/about-codeowners/ 16 | 17 | 18 | # By default the Android Components team will be the owner for everything in 19 | # the repo. Unless a later match takes precedence. 20 | * @mozilla-mobile/act 21 | /automation/ @mozilla-mobile/act 22 | /taskcluster/ @mozilla-mobile/releng @mozilla-mobile/act 23 | /.taskcluster.yml @mozilla-mobile/releng @mozilla-mobile/act 24 | /CODEOWNERS @mozilla-mobile/act 25 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Community Participation Guidelines 2 | 3 | This repository is governed by Mozilla's code of conduct and etiquette guidelines. 4 | For more details, please read the 5 | [Mozilla Community Participation Guidelines](https://www.mozilla.org/about/governance/policies/participation/). 6 | 7 | ## How to Report 8 | For more information on how to report violations of the Community Participation Guidelines, please read our '[How to Report](https://www.mozilla.org/about/governance/policies/participation/reporting/)' page. 9 | 10 | 16 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/lint.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/metrics.yaml: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | $schema: moz://mozilla.org/schemas/glean/metrics/2-0-0 6 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | 23 | -keep class mozilla.appservices.** { *; } 24 | 25 | -dontwarn java.beans.BeanInfo 26 | -dontwarn java.beans.FeatureDescriptor 27 | -dontwarn java.beans.IntrospectionException 28 | -dontwarn java.beans.Introspector 29 | -dontwarn java.beans.PropertyDescriptor 30 | -------------------------------------------------------------------------------- /app/src/androidTest/assets/pages/audioMediaPage.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Audio_Test_Page 4 | 5 | 6 |

Page content: audio player

7 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/androidTest/assets/pages/basic_nav_uuid.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 |

Page content: 3

9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/androidTest/assets/pages/dom_element_focus_test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/androidTest/assets/pages/download.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Page content: web_icon.png 4 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/androidTest/assets/pages/generic1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Test_Page_1 4 | 5 | 6 |

7 |

Page content: 1

8 |

9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/androidTest/assets/pages/generic2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 |

Page content: 2

5 |

6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/androidTest/assets/pages/generic3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

4 |

Page content: 3

5 |

6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/androidTest/assets/pages/generic4.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Test_Page_4 4 | 5 | 6 |

Page content: 4

7 | Link 1 8 | Link 2 9 | Link 3 10 |

11 | 12 | test_link_image 13 | 14 |

15 |

16 | test_no_link_image 17 |

18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/androidTest/assets/pages/lorem-ipsum.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy 7 | eirmod tempor invidunt 8 | 10 | 11 | 12 | 13 | 14 |

Page content: lorem ipsum

15 | 16 |

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt

17 | 18 |

19 | Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy 20 | eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam 21 | voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet 22 | clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit 23 | amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam 24 | nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, 25 | sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. 26 | Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor 27 | sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed 28 | diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, 29 | sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. 30 | Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor 31 | sit amet. 32 |

33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /app/src/androidTest/assets/pages/noControlsVideoMediaPage.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | No_Controls_Video_Test_Page 4 | 5 | 6 |

Page content: video player

7 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/androidTest/assets/pages/refresh.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 42 | 43 |

My little test page - DEFAULT

44 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/androidTest/assets/pages/videoMediaPage.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Video_Test_Page 4 | 5 | 6 |

Page content: video player

7 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/androidTest/assets/resources/audioSample.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/androidTest/assets/resources/audioSample.mp3 -------------------------------------------------------------------------------- /app/src/androidTest/assets/resources/mov_bbb.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/androidTest/assets/resources/mov_bbb.mp4 -------------------------------------------------------------------------------- /app/src/androidTest/assets/resources/rabbit.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/androidTest/assets/resources/rabbit.jpg -------------------------------------------------------------------------------- /app/src/androidTest/assets/resources/web_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/androidTest/assets/resources/web_icon.png -------------------------------------------------------------------------------- /app/src/androidTest/java/org/mozilla/reference/browser/FirefoxTestApplication.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser 6 | 7 | class FirefoxTestApplication : BrowserApplication() 8 | -------------------------------------------------------------------------------- /app/src/androidTest/java/org/mozilla/reference/browser/FirefoxTestRunner.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser 6 | 7 | import android.app.Application 8 | import android.content.Context 9 | import androidx.test.runner.AndroidJUnitRunner 10 | 11 | class FirefoxTestRunner : AndroidJUnitRunner() { 12 | override fun newApplication( 13 | cl: ClassLoader?, 14 | className: String?, 15 | context: Context?, 16 | ): Application = super.newApplication(cl, FirefoxTestApplication::class.java.name, context) 17 | } 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/org/mozilla/reference/browser/ext/UiDevice.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.ext 6 | 7 | import androidx.test.uiautomator.SearchCondition 8 | import androidx.test.uiautomator.UiDevice 9 | import androidx.test.uiautomator.UiObject2 10 | import org.junit.Assert.assertNotNull 11 | import org.mozilla.reference.browser.helpers.TestAssetHelper.waitingTime 12 | 13 | /** 14 | * Wait for an [UiObject2] and perform an interaction on it. 15 | * 16 | * @throws AssertionError if no [UiObject2] matches the condition 17 | */ 18 | fun UiDevice.waitAndInteract( 19 | condition: SearchCondition, 20 | interaction: UiObject2.() -> Unit, 21 | ) { 22 | val obj = this.wait(condition, waitingTime) 23 | assertNotNull(obj) 24 | interaction.invoke(obj) 25 | obj.recycle() 26 | } 27 | -------------------------------------------------------------------------------- /app/src/androidTest/java/org/mozilla/reference/browser/ext/ViewGroup.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.ext 6 | 7 | import android.view.View 8 | import android.view.ViewGroup 9 | 10 | /** 11 | * The [ViewGroup] children as an [Iterable] on [View]s 12 | */ 13 | val ViewGroup.children: Iterable 14 | get() = (0 until childCount).map(this::getChildAt) 15 | -------------------------------------------------------------------------------- /app/src/androidTest/java/org/mozilla/reference/browser/helpers/Assert.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.helpers 6 | 7 | import android.graphics.Bitmap 8 | import android.graphics.Color 9 | import org.junit.Assert.assertEquals 10 | 11 | /** 12 | * Asserts the two bitmaps are the same by ensuring their dimensions, config, and 13 | * pixel data are the same (within the provided delta): this is the same metrics that 14 | * [Bitmap.sameAs] uses. 15 | */ 16 | fun assertEqualsWithDelta( 17 | expectedB: Bitmap, 18 | actualB: Bitmap, 19 | delta: Float, 20 | ) { 21 | assertEquals("widths should be equal", expectedB.width, actualB.width) 22 | assertEquals("heights should be equal", expectedB.height, actualB.height) 23 | assertEquals("config should be equal", expectedB.config, actualB.config) 24 | 25 | for (i in 0 until expectedB.width) { 26 | for (j in 0 until expectedB.height) { 27 | val ePx = expectedB.getPixel(i, j) 28 | val aPx = actualB.getPixel(i, j) 29 | val warn = "Pixel ${i}x$j" 30 | assertEquals("$warn a", Color.alpha(ePx).toFloat(), Color.alpha(aPx).toFloat(), delta) 31 | assertEquals("$warn r", Color.red(ePx).toFloat(), Color.red(aPx).toFloat(), delta) 32 | assertEquals("$warn g", Color.green(ePx).toFloat(), Color.green(aPx).toFloat(), delta) 33 | assertEquals("$warn b", Color.blue(ePx).toFloat(), Color.blue(aPx).toFloat(), delta) 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/androidTest/java/org/mozilla/reference/browser/helpers/BrowserActivityTestRule.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | @file:Suppress("DEPRECATION") 6 | 7 | package org.mozilla.reference.browser.helpers 8 | 9 | import androidx.test.espresso.IdlingRegistry 10 | import androidx.test.rule.ActivityTestRule 11 | import org.mozilla.reference.browser.BrowserActivity 12 | 13 | /** 14 | * A [org.junit.Rule] to handle shared test set up for tests on [BrowserActivity]. 15 | * 16 | * @param initialTouchMode See [ActivityTestRule] 17 | * @param launchActivity See [ActivityTestRule] 18 | */ 19 | class BrowserActivityTestRule( 20 | initialTouchMode: Boolean = false, 21 | launchActivity: Boolean = true, 22 | ) : ActivityTestRule(BrowserActivity::class.java, initialTouchMode, launchActivity) { 23 | /** 24 | * Ensures the test doesn't advance until session page load is completed. 25 | * 26 | * N.B.: in the current implementation, tests pass without this so it seems to be 27 | * unnecessary: I think this is because the progress bar animation acts as the 28 | * necessary idling resource. However, we leave this in just in case the 29 | * implementation changes and the tests break. In that case, this code might be 30 | * broken because it's not used, and thus tested, at present. 31 | */ 32 | 33 | private lateinit var loadingIdlingResource: SessionLoadedIdlingResource 34 | 35 | override fun beforeActivityLaunched() { 36 | loadingIdlingResource = SessionLoadedIdlingResource().also { 37 | IdlingRegistry.getInstance().register(it) 38 | } 39 | } 40 | 41 | override fun afterActivityFinished() { 42 | IdlingRegistry.getInstance().unregister(loadingIdlingResource) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/androidTest/java/org/mozilla/reference/browser/helpers/Constants.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.helpers 6 | 7 | object Constants { 8 | const val LONG_CLICK_DURATION: Long = 5000 9 | } 10 | -------------------------------------------------------------------------------- /app/src/androidTest/java/org/mozilla/reference/browser/helpers/RetryTestRule.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.helpers 6 | 7 | import androidx.test.espresso.NoMatchingViewException 8 | import androidx.test.uiautomator.UiObjectNotFoundException 9 | import org.junit.rules.TestRule 10 | import org.junit.runner.Description 11 | import org.junit.runners.model.Statement 12 | import java.lang.AssertionError 13 | 14 | class RetryTestRule( 15 | private val retryCount: Int = 5, 16 | ) : TestRule { 17 | override fun apply( 18 | base: Statement, 19 | description: Description, 20 | ): Statement = 21 | statement { 22 | for (i in 1..retryCount) { 23 | try { 24 | base.evaluate() 25 | break 26 | } catch (t: AssertionError) { 27 | if (i == retryCount) { 28 | throw t 29 | } 30 | } catch (t: UiObjectNotFoundException) { 31 | if (i == retryCount) { 32 | throw t 33 | } 34 | } catch (t: NoMatchingViewException) { 35 | if (i == retryCount) { 36 | throw t 37 | } 38 | } 39 | } 40 | } 41 | 42 | private inline fun statement(crossinline eval: () -> Unit): Statement = 43 | object : Statement() { 44 | override fun evaluate() = eval() 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/androidTest/java/org/mozilla/reference/browser/helpers/SessionLoadedIdlingResource.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.helpers 6 | 7 | import androidx.test.espresso.IdlingResource 8 | import androidx.test.platform.app.InstrumentationRegistry 9 | import mozilla.components.browser.state.selector.selectedTab 10 | import org.mozilla.reference.browser.BrowserApplication 11 | 12 | /** 13 | * An IdlingResource implementation that waits until the current session is not loading anymore. 14 | * Only after loading has completed further actions will be performed. 15 | */ 16 | 17 | class SessionLoadedIdlingResource : IdlingResource { 18 | private var resourceCallback: IdlingResource.ResourceCallback? = null 19 | 20 | override fun getName(): String = SessionLoadedIdlingResource::class.java.simpleName 21 | 22 | override fun isIdleNow(): Boolean { 23 | val context = InstrumentationRegistry.getInstrumentation().targetContext.applicationContext 24 | as BrowserApplication 25 | 26 | val store = context.components.core.store 27 | 28 | return if (store.state.selectedTab 29 | ?.content 30 | ?.loading == true 31 | ) { 32 | false 33 | } else { 34 | invokeCallback() 35 | true 36 | } 37 | } 38 | 39 | private fun invokeCallback() { 40 | if (resourceCallback != null) { 41 | resourceCallback!!.onTransitionToIdle() 42 | } 43 | } 44 | 45 | override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback) { 46 | this.resourceCallback = callback 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/androidTest/java/org/mozilla/reference/browser/helpers/ext/String.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.helpers.ext 6 | 7 | import android.net.Uri 8 | 9 | // Extension functions for the String class 10 | 11 | fun String?.toUri(): Uri? = 12 | if (this == null) { 13 | null 14 | } else { 15 | Uri.parse(this) 16 | } 17 | -------------------------------------------------------------------------------- /app/src/androidTest/java/org/mozilla/reference/browser/helpers/ext/ViewInteraction.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.helpers 6 | 7 | import androidx.test.espresso.ViewInteraction 8 | import androidx.test.espresso.action.ViewActions 9 | import androidx.test.espresso.assertion.ViewAssertions.matches 10 | 11 | fun ViewInteraction.click(): ViewInteraction = this.perform(ViewActions.click())!! 12 | 13 | fun ViewInteraction.assertIsEnabled(isEnabled: Boolean): ViewInteraction = this.check(matches(isEnabled(isEnabled)))!! 14 | 15 | fun ViewInteraction.assertIsChecked(isChecked: Boolean): ViewInteraction = this.check(matches(isChecked(isChecked)))!! 16 | 17 | fun ViewInteraction.assertIsSelected(isSelected: Boolean): ViewInteraction = 18 | this.check(matches(isSelected(isSelected)))!! 19 | -------------------------------------------------------------------------------- /app/src/androidTest/java/org/mozilla/reference/browser/helpers/matchers/TabMatcher.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.helpers.matchers 6 | 7 | import android.view.View 8 | import android.widget.TextView 9 | import org.hamcrest.Description 10 | import org.hamcrest.Matcher 11 | import org.hamcrest.TypeSafeMatcher 12 | import org.mozilla.reference.browser.R 13 | 14 | /** 15 | * A custom matcher for finding tabs to match text within them. 16 | */ 17 | class TabMatcher( 18 | val id: Int, 19 | val matcher: (T) -> Boolean, 20 | ) : TypeSafeMatcher() { 21 | override fun describeTo(description: Description?) { 22 | description?.appendText("with expected tab item") 23 | } 24 | 25 | override fun matchesSafely(item: T): Boolean { 26 | val result = item.id == id 27 | 28 | // early return if the ID does not match makes the test run faster. 29 | if (!result) { 30 | return false 31 | } 32 | 33 | return matcher(item) 34 | } 35 | 36 | companion object { 37 | fun withText(text: String): Matcher = 38 | TabMatcher( 39 | R.id.mozac_browser_tabstray_title, 40 | ) { 41 | (it as TextView).text == text 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/androidTest/java/org/mozilla/reference/browser/ui/SearchTest.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.ui 6 | 7 | import okhttp3.mockwebserver.MockWebServer 8 | import org.junit.After 9 | import org.junit.Before 10 | import org.junit.Rule 11 | import org.junit.Test 12 | import org.mozilla.reference.browser.helpers.AndroidAssetDispatcher 13 | import org.mozilla.reference.browser.helpers.BrowserActivityTestRule 14 | import org.mozilla.reference.browser.helpers.RetryTestRule 15 | import org.mozilla.reference.browser.helpers.TestAssetHelper 16 | import org.mozilla.reference.browser.ui.robots.navigationToolbar 17 | 18 | class SearchTest { 19 | private lateinit var mockWebServer: MockWebServer 20 | 21 | @get:Rule 22 | val activityTestRule = BrowserActivityTestRule() 23 | 24 | @Rule 25 | @JvmField 26 | val retryTestRule = RetryTestRule(3) 27 | 28 | @Before 29 | fun setUp() { 30 | mockWebServer = MockWebServer().apply { 31 | dispatcher = AndroidAssetDispatcher() 32 | start() 33 | } 34 | } 35 | 36 | @After 37 | fun tearDown() { 38 | mockWebServer.shutdown() 39 | } 40 | 41 | @Test 42 | fun siteSearchSuggestionTest() { 43 | val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) 44 | 45 | navigationToolbar { 46 | }.enterUrlAndEnterToBrowser(defaultWebPage.url) { 47 | } 48 | navigationToolbar { 49 | }.openTabTrayMenu { 50 | }.openNewTab { 51 | }.clickToolbar { 52 | typeText("generic1.html") 53 | verifySearchSuggestion(defaultWebPage.title) 54 | }.clickSearchSuggestion(defaultWebPage.title) { 55 | verifyUrl(defaultWebPage.url.toString()) 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /app/src/androidTest/java/org/mozilla/reference/browser/ui/robots/AddToHomeScreenRobot.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.ui.robots 6 | 7 | import androidx.test.uiautomator.UiSelector 8 | import org.mozilla.reference.browser.helpers.TestAssetHelper.waitingTime 9 | 10 | /** 11 | * Implementation of Robot Pattern for the Add to homescreen feature. 12 | */ 13 | class AddToHomeScreenRobot { 14 | fun clickCancelAddToHomeScreenButton() { 15 | cancelAddToHomeScreenButton().waitForExists(waitingTime) 16 | cancelAddToHomeScreenButton().click() 17 | } 18 | 19 | fun clickAddAutomaticallyToHomeScreenButton() { 20 | addAutomaticallyToHomeScreenButton().waitForExists(waitingTime) 21 | addAutomaticallyToHomeScreenButton().click() 22 | } 23 | 24 | class Transition { 25 | fun openHomeScreenShortcut( 26 | title: String, 27 | interact: BrowserRobot.() -> Unit, 28 | ): BrowserRobot.Transition { 29 | mDevice.findObject(UiSelector().textContains(title)).waitForExists(waitingTime) 30 | mDevice.findObject((UiSelector().textContains(title))).clickAndWaitForNewWindow(waitingTime) 31 | 32 | BrowserRobot().interact() 33 | return BrowserRobot.Transition() 34 | } 35 | } 36 | 37 | private fun cancelAddToHomeScreenButton() = mDevice.findObject(UiSelector().textContains("CANCEL")) 38 | 39 | private fun addAutomaticallyToHomeScreenButton() = 40 | mDevice.findObject(UiSelector().textContains("ADD AUTOMATICALLY")) 41 | } 42 | -------------------------------------------------------------------------------- /app/src/androidTest/java/org/mozilla/reference/browser/ui/robots/ContentPanelRobot.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.ui.robots 6 | 7 | import androidx.test.platform.app.InstrumentationRegistry 8 | import androidx.test.uiautomator.UiDevice 9 | import androidx.test.uiautomator.UiSelector 10 | import org.junit.Assert.assertTrue 11 | import org.mozilla.reference.browser.helpers.TestAssetHelper.waitingTime 12 | 13 | /** 14 | * Implementation of Robot Pattern for the content panel. 15 | */ 16 | class ContentPanelRobot { 17 | fun verifyShareContentPanel() = assertShareContentPanel() 18 | 19 | class Transition { 20 | val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) 21 | 22 | fun contentPanel(): ContentPanelRobot.Transition { 23 | mDevice.waitForIdle() 24 | return ContentPanelRobot.Transition() 25 | } 26 | } 27 | } 28 | 29 | private fun assertShareContentPanel() { 30 | mDevice.waitForIdle() 31 | assertTrue(mDevice.findObject(UiSelector().textContains("Share")).waitForExists(waitingTime)) 32 | mDevice.pressBack() 33 | } 34 | -------------------------------------------------------------------------------- /app/src/androidTest/java/org/mozilla/reference/browser/ui/robots/DownloadRobot.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.ui.robots 6 | 7 | import androidx.test.uiautomator.UiSelector 8 | import org.mozilla.reference.browser.helpers.TestAssetHelper.waitingTime 9 | import org.mozilla.reference.browser.helpers.TestHelper.packageName 10 | 11 | class DownloadRobot { 12 | fun cancelDownload() { 13 | closeDownloadButton.waitForExists(waitingTime) 14 | closeDownloadButton.click() 15 | } 16 | 17 | fun confirmDownload() { 18 | downloadButton.waitForExists(waitingTime) 19 | downloadButton.click() 20 | } 21 | 22 | class Transition 23 | } 24 | 25 | fun downloadRobot(interact: DownloadRobot.() -> Unit): DownloadRobot.Transition { 26 | DownloadRobot().interact() 27 | return DownloadRobot.Transition() 28 | } 29 | 30 | private val closeDownloadButton = mDevice.findObject(UiSelector().resourceId("$packageName:id/close_button")) 31 | private val downloadButton = mDevice.findObject(UiSelector().resourceId("$packageName:id/download_button")) 32 | -------------------------------------------------------------------------------- /app/src/androidTest/java/org/mozilla/reference/browser/ui/robots/SyncedTabsRobot.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.ui.robots 6 | 7 | import androidx.test.uiautomator.UiSelector 8 | import org.junit.Assert.assertTrue 9 | import org.mozilla.reference.browser.R 10 | import org.mozilla.reference.browser.helpers.TestAssetHelper.waitingTime 11 | import org.mozilla.reference.browser.helpers.TestHelper.getStringResource 12 | import org.mozilla.reference.browser.helpers.TestHelper.packageName 13 | 14 | /** 15 | * Implementation of Robot Pattern for Synced Tabs sub menu. 16 | */ 17 | class SyncedTabsRobot { 18 | fun verifyNotSignedInSyncTabsView() = assertNotSignedInSyncTabsView() 19 | 20 | class Transition { 21 | fun syncedTabs(interact: SyncedTabsRobot.() -> Unit): SyncedTabsRobot.Transition { 22 | SyncedTabsRobot().interact() 23 | return SyncedTabsRobot.Transition() 24 | } 25 | } 26 | 27 | private fun assertNotSignedInSyncTabsView() { 28 | assertTrue( 29 | mDevice 30 | .findObject( 31 | UiSelector() 32 | .resourceId("$packageName:id/synced_tabs_status") 33 | .textContains(getStringResource(R.string.synced_tabs_connect_to_sync_account)), 34 | ).waitForExists(waitingTime), 35 | ) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/androidTest/java/org/mozilla/reference/browser/ui/robots/TabTrayMoreOptionsMenuRobot.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.ui.robots 6 | 7 | import androidx.test.espresso.Espresso.onView 8 | import androidx.test.espresso.assertion.ViewAssertions 9 | import androidx.test.espresso.matcher.ViewMatchers 10 | import androidx.test.platform.app.InstrumentationRegistry 11 | import androidx.test.uiautomator.By 12 | import androidx.test.uiautomator.UiDevice 13 | import androidx.test.uiautomator.Until 14 | import org.mozilla.reference.browser.ext.waitAndInteract 15 | import org.mozilla.reference.browser.helpers.click 16 | 17 | /** 18 | * Implementation of Robot Pattern for menu in tab tray that shows more options. 19 | * So far only Close All Tabs is implemented. 20 | */ 21 | 22 | class TabTrayMoreOptionsMenuRobot { 23 | fun verifyCloseAllTabsButton() = assertCloseAllTabsButton() 24 | 25 | fun verifyCloseAllPrivateTabsButton() = assertCloseAllPrivateTabsButton() 26 | 27 | class Transition { 28 | val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) 29 | 30 | fun closeAllTabs(interact: NavigationToolbarRobot.() -> Unit): NavigationToolbarRobot { 31 | mDevice.waitForIdle() 32 | closeAllTabsButton().click() 33 | NavigationToolbarRobot().interact() 34 | return NavigationToolbarRobot() 35 | } 36 | 37 | fun closeAllPrivateTabs(interact: NavigationToolbarRobot.() -> Unit): NavigationToolbarRobot.Transition { 38 | mDevice.waitForIdle() 39 | closeAllPrivateTabsButton().click() 40 | NavigationToolbarRobot().interact() 41 | return NavigationToolbarRobot.Transition() 42 | } 43 | } 44 | } 45 | 46 | private fun closeAllTabsButton() = onView(ViewMatchers.withText("Close All Tabs")) 47 | 48 | private fun closeAllPrivateTabsButton() = onView(ViewMatchers.withText("Close Private Tabs")) 49 | 50 | private fun assertCloseAllTabsButton() { 51 | val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) 52 | mDevice.waitAndInteract(Until.findObject(By.text("Close All Tabs"))) {} 53 | } 54 | 55 | private fun assertCloseAllPrivateTabsButton() = 56 | closeAllPrivateTabsButton() 57 | .check(ViewAssertions.matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) 58 | -------------------------------------------------------------------------------- /app/src/debug/res/mipmap-hdpi/ic_icon_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/debug/res/mipmap-hdpi/ic_icon_background.png -------------------------------------------------------------------------------- /app/src/debug/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/debug/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/debug/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/debug/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/debug/res/mipmap-mdpi/ic_icon_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/debug/res/mipmap-mdpi/ic_icon_background.png -------------------------------------------------------------------------------- /app/src/debug/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/debug/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/debug/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/debug/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/debug/res/mipmap-xhdpi/ic_icon_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/debug/res/mipmap-xhdpi/ic_icon_background.png -------------------------------------------------------------------------------- /app/src/debug/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/debug/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/debug/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/debug/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/debug/res/mipmap-xxhdpi/ic_icon_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/debug/res/mipmap-xxhdpi/ic_icon_background.png -------------------------------------------------------------------------------- /app/src/debug/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/debug/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/debug/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/debug/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/debug/res/mipmap-xxxhdpi/ic_icon_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/debug/res/mipmap-xxxhdpi/ic_icon_background.png -------------------------------------------------------------------------------- /app/src/debug/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/debug/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/debug/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/debug/res/values/firebase.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 973845059695-vgd2p0n78butpgcdbid910jectr92g8j.apps.googleusercontent.com 10 | https://boxwood-axon-825.firebaseio.com 11 | 973845059695 12 | AIzaSyBpkiYO2lDh3wR0u-Xnf1871E5-DGQRv1c 13 | 1:973845059695:android:b5e9b3fcd0cd86f3 14 | AIzaSyBpkiYO2lDh3wR0u-Xnf1871E5-DGQRv1c 15 | boxwood-axon-825.appspot.com 16 | boxwood-axon-825 17 | -------------------------------------------------------------------------------- /app/src/main/java/mozilla/components/lib/state/Store.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package mozilla.components.lib.state 6 | 7 | import androidx.compose.runtime.Composable 8 | import androidx.compose.runtime.mutableStateOf 9 | import androidx.compose.runtime.remember 10 | import androidx.lifecycle.Lifecycle 11 | import androidx.lifecycle.LifecycleOwner 12 | import androidx.lifecycle.compose.LocalLifecycleOwner 13 | import mozilla.components.lib.state.ext.observe 14 | import androidx.compose.runtime.State as ComposeState 15 | 16 | /** 17 | * Starts observing this [Store] and represents the mapped state (using [map]) via [ComposeState]. 18 | * Every time the [Store] state changes the returned [ComposeState] will be updated causing 19 | * recomposition of every [ComposeState.value] usage. 20 | * 21 | * The [Store] observer will automatically be removed when this composable disposes or the current 22 | * [LifecycleOwner] moves to the [Lifecycle.State.DESTROYED] state. 23 | */ 24 | @Composable 25 | fun Store.observeAsState(map: (S) -> R): ComposeState { 26 | val lifecycleOwner = LocalLifecycleOwner.current 27 | val state = remember { mutableStateOf(map(state)) } 28 | 29 | observe(lifecycleOwner) { browserState -> 30 | state.value = map(browserState) 31 | } 32 | 33 | return state 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/BrowserTestActivity.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser 6 | 7 | import android.app.Activity 8 | import android.content.Intent 9 | import android.os.Bundle 10 | import org.mozilla.reference.browser.ext.components 11 | 12 | /** 13 | * This activity is used for performance testing with Raptor/tp6: 14 | * https://wiki.mozilla.org/Performance_sheriffing/Raptor 15 | */ 16 | class BrowserTestActivity : Activity() { 17 | override fun onCreate(savedInstanceState: Bundle?) { 18 | super.onCreate(savedInstanceState) 19 | 20 | // We're creating a default session here so that we don't end up 21 | // with a gecko session that we don't manage. We want to receive 22 | // callbacks to update the UI (toolbar) which might have an impact 23 | // on performance as well (e.g. progress bar animations). 24 | components.useCases.tabsUseCases.addTab("about:blank") 25 | 26 | startActivity(Intent(this, BrowserActivity::class.java)) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/CrashListActivity.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser 6 | 7 | import android.content.Intent 8 | import android.os.Bundle 9 | import androidx.appcompat.app.AppCompatActivity 10 | import androidx.core.net.toUri 11 | import mozilla.components.lib.crash.CrashReporter 12 | import mozilla.components.lib.crash.ui.AbstractCrashListFragment 13 | import org.mozilla.reference.browser.ext.requireComponents 14 | 15 | /** 16 | * A simple activity whose only purpose is to load the [CrashListFragment]. 17 | */ 18 | class CrashListActivity : AppCompatActivity() { 19 | override fun onCreate(savedInstanceState: Bundle?) { 20 | super.onCreate(savedInstanceState) 21 | 22 | packageName 23 | supportFragmentManager 24 | .beginTransaction() 25 | .add(android.R.id.content, CrashListFragment()) 26 | .commit() 27 | } 28 | } 29 | 30 | /** 31 | * An [AbstractCrashListFragment] implementor that uses the application [CrashReporter]. 32 | */ 33 | class CrashListFragment : AbstractCrashListFragment() { 34 | override val reporter: CrashReporter by lazy { requireComponents.analytics.crashReporter } 35 | 36 | override fun onCrashServiceSelected(url: String) { 37 | val intent = Intent(Intent.ACTION_VIEW).apply { 38 | data = url.toUri() 39 | `package` = context?.packageName 40 | } 41 | startActivity(intent) 42 | activity?.finish() 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/EngineProvider.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser 6 | 7 | import android.content.Context 8 | import mozilla.components.browser.engine.gecko.GeckoEngine 9 | import mozilla.components.browser.engine.gecko.fetch.GeckoViewFetchClient 10 | import mozilla.components.concept.engine.DefaultSettings 11 | import mozilla.components.concept.engine.Engine 12 | import mozilla.components.concept.fetch.Client 13 | import mozilla.components.feature.webcompat.WebCompatFeature 14 | import mozilla.components.lib.crash.handler.CrashHandlerService 15 | import org.mozilla.geckoview.GeckoRuntime 16 | import org.mozilla.geckoview.GeckoRuntimeSettings 17 | 18 | object EngineProvider { 19 | private var runtime: GeckoRuntime? = null 20 | 21 | @Synchronized 22 | fun getOrCreateRuntime(context: Context): GeckoRuntime { 23 | if (runtime == null) { 24 | val builder = GeckoRuntimeSettings.Builder() 25 | 26 | builder.crashHandler(CrashHandlerService::class.java) 27 | 28 | // About config it's no longer enabled by default 29 | builder.aboutConfigEnabled(true) 30 | builder.extensionsWebAPIEnabled(true) 31 | runtime = GeckoRuntime.create(context, builder.build()) 32 | } 33 | 34 | return runtime!! 35 | } 36 | 37 | fun createEngine( 38 | context: Context, 39 | defaultSettings: DefaultSettings, 40 | ): Engine { 41 | val runtime = getOrCreateRuntime(context) 42 | 43 | return GeckoEngine(context, defaultSettings, runtime).also { 44 | WebCompatFeature.install(it) 45 | } 46 | } 47 | 48 | fun createClient(context: Context): Client { 49 | val runtime = getOrCreateRuntime(context) 50 | return GeckoViewFetchClient(context, runtime) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/ExternalAppBrowserActivity.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser 6 | 7 | import androidx.core.net.toUri 8 | import androidx.fragment.app.Fragment 9 | import mozilla.components.concept.engine.manifest.WebAppManifest 10 | import mozilla.components.feature.pwa.ext.getWebAppManifest 11 | import org.mozilla.reference.browser.browser.ExternalAppBrowserFragment 12 | 13 | /** 14 | * Activity that holds the BrowserFragment that is launched within an external app, 15 | * such as custom tabs and progressive web apps. 16 | */ 17 | class ExternalAppBrowserActivity : BrowserActivity() { 18 | override fun createBrowserFragment(sessionId: String?): Fragment = 19 | if (sessionId != null) { 20 | val manifest = intent.getWebAppManifest() 21 | val scope = when (manifest?.display) { 22 | WebAppManifest.DisplayMode.FULLSCREEN, 23 | WebAppManifest.DisplayMode.STANDALONE, 24 | -> (manifest.scope ?: manifest.startUrl).toUri() 25 | 26 | WebAppManifest.DisplayMode.MINIMAL_UI, 27 | WebAppManifest.DisplayMode.BROWSER, 28 | -> null 29 | else -> null 30 | } 31 | 32 | ExternalAppBrowserFragment.create( 33 | sessionId, 34 | manifest, 35 | listOfNotNull(scope), 36 | ) 37 | } else { 38 | // Fall back to browser fragment 39 | super.createBrowserFragment(sessionId) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/IntentReceiverActivity.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser 6 | 7 | import android.app.Activity 8 | import android.content.Intent 9 | import android.os.Bundle 10 | import kotlinx.coroutines.MainScope 11 | import kotlinx.coroutines.launch 12 | import org.mozilla.reference.browser.ext.components 13 | 14 | class IntentReceiverActivity : Activity() { 15 | override fun onCreate(savedInstanceState: Bundle?) { 16 | super.onCreate(savedInstanceState) 17 | val intent = intent?.let { Intent(it) } ?: Intent() 18 | 19 | // Explicitly remove the new task and clear task flags (Our browser activity is a single 20 | // task activity and we never want to start a second task here). 21 | intent.flags = intent.flags and Intent.FLAG_ACTIVITY_NEW_TASK.inv() 22 | intent.flags = intent.flags and Intent.FLAG_ACTIVITY_CLEAR_TASK.inv() 23 | 24 | // LauncherActivity is started with the "excludeFromRecents" flag (set in manifest). We 25 | // do not want to propagate this flag from the launcher activity to the browser. 26 | intent.flags = intent.flags and Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS.inv() 27 | 28 | val utils = components.utils 29 | 30 | MainScope().launch { 31 | val processor = utils.intentProcessors.firstOrNull { it.process(intent) } 32 | 33 | val className = if (processor in utils.externalIntentProcessors) { 34 | ExternalAppBrowserActivity::class 35 | } else { 36 | BrowserActivity::class 37 | } 38 | 39 | intent.setClassName(applicationContext, className.java.name) 40 | 41 | startActivity(intent) 42 | finish() 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/IntentRequestCodes.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser 6 | 7 | object IntentRequestCodes { 8 | const val REQUEST_CODE_DATA_REPORTING = 0 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/addons/AddonsActivity.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.addons 6 | 7 | import android.os.Bundle 8 | import androidx.appcompat.app.AppCompatActivity 9 | import org.mozilla.reference.browser.R 10 | 11 | /** 12 | * An activity to manage add-ons. 13 | */ 14 | class AddonsActivity : AppCompatActivity() { 15 | override fun onCreate(savedInstanceState: Bundle?) { 16 | super.onCreate(savedInstanceState) 17 | setContentView(R.layout.activity_main) 18 | 19 | if (savedInstanceState == null) { 20 | supportFragmentManager.beginTransaction().apply { 21 | replace(R.id.container, AddonsFragment()) 22 | commit() 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/addons/Extensions.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.addons 6 | 7 | import androidx.fragment.app.Fragment 8 | import java.text.NumberFormat 9 | import java.util.Locale 10 | 11 | internal fun getFormattedAmount(amount: Int): String = 12 | NumberFormat.getNumberInstance(Locale.getDefault()).format(amount) 13 | 14 | /** 15 | * Run the [block] only if the [Fragment] is attached. 16 | * 17 | * @param block A callback to be executed if the container [Fragment] is attached. 18 | */ 19 | internal inline fun Fragment.runIfFragmentIsAttached(block: () -> Unit) { 20 | context?.let { 21 | block() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/autofill/AutofillConfirmActivity.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.autofill 6 | 7 | import android.os.Build 8 | import androidx.annotation.RequiresApi 9 | import mozilla.components.feature.autofill.AutofillConfiguration 10 | import mozilla.components.feature.autofill.ui.AbstractAutofillConfirmActivity 11 | import org.mozilla.reference.browser.ext.components 12 | 13 | @RequiresApi(Build.VERSION_CODES.O) 14 | class AutofillConfirmActivity : AbstractAutofillConfirmActivity() { 15 | override val configuration: AutofillConfiguration by lazy { components.autofillConfiguration } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/autofill/AutofillPreference.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.autofill 6 | 7 | import android.content.Context 8 | import android.content.Intent 9 | import android.os.Build 10 | import android.provider.Settings 11 | import android.util.AttributeSet 12 | import android.view.autofill.AutofillManager 13 | import androidx.annotation.RequiresApi 14 | import androidx.appcompat.widget.SwitchCompat 15 | import androidx.core.net.toUri 16 | import androidx.preference.Preference 17 | import androidx.preference.PreferenceViewHolder 18 | import org.mozilla.reference.browser.R 19 | 20 | class AutofillPreference 21 | @JvmOverloads 22 | constructor( 23 | context: Context, 24 | attrs: AttributeSet? = null, 25 | ) : Preference(context, attrs) { 26 | private var switchView: SwitchCompat? = null 27 | 28 | init { 29 | widgetLayoutResource = R.layout.preference_autofill 30 | } 31 | 32 | override fun onBindViewHolder(holder: PreferenceViewHolder) { 33 | super.onBindViewHolder(holder) 34 | switchView = holder.findViewById(R.id.switch_widget) as SwitchCompat 35 | 36 | updateSwitch() 37 | } 38 | 39 | fun updateSwitch() { 40 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { 41 | return 42 | } 43 | 44 | val autofillManager = context.getSystemService(AutofillManager::class.java) 45 | switchView?.isChecked = autofillManager.hasEnabledAutofillServices() 46 | } 47 | 48 | @RequiresApi(Build.VERSION_CODES.O) 49 | override fun onClick() { 50 | val intent = Intent(Settings.ACTION_REQUEST_SET_AUTOFILL_SERVICE).apply { 51 | data = "package:${context.packageName}".toUri() 52 | } 53 | context.startActivity(intent) 54 | } 55 | 56 | companion object { 57 | fun isSupported(context: Context): Boolean { 58 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { 59 | return false 60 | } 61 | 62 | val autofillManager = context.getSystemService(AutofillManager::class.java) 63 | return autofillManager.isAutofillSupported 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/autofill/AutofillSearchActivity.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.autofill 6 | 7 | import android.os.Build 8 | import android.os.Bundle 9 | import android.view.ViewGroup 10 | import androidx.annotation.RequiresApi 11 | import mozilla.components.feature.autofill.AutofillConfiguration 12 | import mozilla.components.feature.autofill.ui.AbstractAutofillSearchActivity 13 | import org.mozilla.reference.browser.ext.components 14 | 15 | @RequiresApi(Build.VERSION_CODES.O) 16 | class AutofillSearchActivity : AbstractAutofillSearchActivity() { 17 | override val configuration: AutofillConfiguration by lazy { components.autofillConfiguration } 18 | 19 | override fun onCreate(savedInstanceState: Bundle?) { 20 | super.onCreate(savedInstanceState) 21 | 22 | // To avoid the dialog constantly resizing horizontally while typing, let's always use 23 | // the full width of the screen for the dialog. 24 | window.setLayout( 25 | ViewGroup.LayoutParams.MATCH_PARENT, 26 | ViewGroup.LayoutParams.WRAP_CONTENT, 27 | ) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/autofill/AutofillService.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.autofill 6 | 7 | import android.os.Build 8 | import androidx.annotation.RequiresApi 9 | import mozilla.components.feature.autofill.AbstractAutofillService 10 | import mozilla.components.feature.autofill.AutofillConfiguration 11 | import org.mozilla.reference.browser.ext.components 12 | 13 | @RequiresApi(Build.VERSION_CODES.O) 14 | class AutofillService : AbstractAutofillService() { 15 | override val configuration: AutofillConfiguration by lazy { components.autofillConfiguration } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/autofill/AutofillUnlockActivity.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.autofill 6 | 7 | import android.os.Build 8 | import androidx.annotation.RequiresApi 9 | import mozilla.components.feature.autofill.AutofillConfiguration 10 | import mozilla.components.feature.autofill.ui.AbstractAutofillUnlockActivity 11 | import org.mozilla.reference.browser.ext.components 12 | 13 | @RequiresApi(Build.VERSION_CODES.O) 14 | class AutofillUnlockActivity : AbstractAutofillUnlockActivity() { 15 | override val configuration: AutofillConfiguration by lazy { components.autofillConfiguration } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/browser/CrashIntegration.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.browser 6 | 7 | import android.content.BroadcastReceiver 8 | import android.content.Context 9 | import android.content.Intent 10 | import android.content.IntentFilter 11 | import androidx.core.content.ContextCompat 12 | import androidx.lifecycle.DefaultLifecycleObserver 13 | import androidx.lifecycle.LifecycleOwner 14 | import kotlinx.coroutines.DelicateCoroutinesApi 15 | import kotlinx.coroutines.GlobalScope 16 | import kotlinx.coroutines.launch 17 | import mozilla.components.lib.crash.Crash 18 | import mozilla.components.lib.crash.CrashReporter 19 | import mozilla.components.support.utils.ext.registerReceiverCompat 20 | import org.mozilla.reference.browser.BrowserApplication.Companion.NON_FATAL_CRASH_BROADCAST 21 | 22 | class CrashIntegration( 23 | private val context: Context, 24 | private val crashReporter: CrashReporter, 25 | private val onCrash: (Crash) -> Unit, 26 | ) : DefaultLifecycleObserver { 27 | private val receiver = object : BroadcastReceiver() { 28 | override fun onReceive( 29 | context: Context, 30 | intent: Intent, 31 | ) { 32 | if (!Crash.isCrashIntent(intent)) { 33 | return 34 | } 35 | 36 | val crash = Crash.fromIntent(intent) 37 | onCrash(crash) 38 | } 39 | } 40 | 41 | override fun onStart(owner: LifecycleOwner) { 42 | super.onStart(owner) 43 | context.registerReceiverCompat( 44 | receiver, 45 | IntentFilter(NON_FATAL_CRASH_BROADCAST), 46 | ContextCompat.RECEIVER_NOT_EXPORTED, 47 | ) 48 | } 49 | 50 | override fun onStop(owner: LifecycleOwner) { 51 | super.onStop(owner) 52 | context.unregisterReceiver(receiver) 53 | } 54 | 55 | @OptIn(DelicateCoroutinesApi::class) 56 | fun sendCrashReport(crash: Crash) { 57 | GlobalScope.launch { 58 | crashReporter.submitReport(crash) 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/components/Push.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.components 6 | 7 | import android.annotation.SuppressLint 8 | import android.content.Context 9 | import mozilla.components.feature.push.AutoPushFeature 10 | import mozilla.components.feature.push.PushConfig 11 | import mozilla.components.lib.crash.CrashReporter 12 | import mozilla.components.support.base.log.logger.Logger 13 | import org.mozilla.reference.browser.push.FirebasePush 14 | 15 | /** 16 | * Component group for push services. These components use services that strongly depend on 17 | * push messaging (e.g. WebPush, SendTab). 18 | */ 19 | @SuppressLint("DiscouragedApi") 20 | class Push( 21 | context: Context, 22 | crashReporter: CrashReporter, 23 | ) { 24 | val feature by lazy { 25 | pushConfig?.let { config -> 26 | AutoPushFeature( 27 | context = context, 28 | service = pushService, 29 | config = config, 30 | crashReporter = crashReporter, 31 | ) 32 | } 33 | } 34 | 35 | /** 36 | * The push configuration data class used to initialize the AutoPushFeature. 37 | * 38 | * If we have the `project_id` resource, then we know that the Firebase configuration and API 39 | * keys are available for the FCM service to be used. 40 | */ 41 | private val pushConfig by lazy { 42 | val logger = Logger("AutoPush") 43 | 44 | val resId = context.resources.getIdentifier("project_id", "string", context.packageName) 45 | if (resId == 0) { 46 | logger.info("No push keys found. Exiting..") 47 | return@lazy null 48 | } 49 | logger.info("Push keys detected, instantiation beginning..") 50 | val projectId = context.resources.getString(resId) 51 | PushConfig(projectId) 52 | } 53 | 54 | private val pushService by lazy { FirebasePush() } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/components/Services.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.components 6 | 7 | import android.content.Context 8 | import androidx.preference.PreferenceManager 9 | import kotlinx.coroutines.MainScope 10 | import kotlinx.coroutines.launch 11 | import mozilla.components.feature.accounts.FirefoxAccountsAuthFeature 12 | import mozilla.components.feature.app.links.AppLinksInterceptor 13 | import mozilla.components.feature.tabs.TabsUseCases 14 | import mozilla.components.service.fxa.manager.FxaAccountManager 15 | import org.mozilla.reference.browser.R 16 | import org.mozilla.reference.browser.ext.getPreferenceKey 17 | 18 | /** 19 | * Component group which encapsulates foreground-friendly services. 20 | */ 21 | class Services( 22 | private val context: Context, 23 | private val accountManager: FxaAccountManager, 24 | private val tabsUseCases: TabsUseCases, 25 | ) { 26 | private val prefs = PreferenceManager.getDefaultSharedPreferences(context) 27 | val accountsAuthFeature by lazy { 28 | FirefoxAccountsAuthFeature( 29 | accountManager, 30 | redirectUrl = BackgroundServices.REDIRECT_URL, 31 | ) { _, authUrl -> 32 | MainScope().launch { 33 | tabsUseCases.addTab.invoke(authUrl) 34 | } 35 | } 36 | } 37 | 38 | val appLinksInterceptor by lazy { 39 | AppLinksInterceptor( 40 | context, 41 | launchInApp = { 42 | prefs.getBoolean(context.getPreferenceKey(R.string.pref_key_launch_external_app), false) 43 | }, 44 | ) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/components/Utilities.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.components 6 | 7 | import android.content.Context 8 | import mozilla.components.browser.state.store.BrowserStore 9 | import mozilla.components.feature.customtabs.CustomTabIntentProcessor 10 | import mozilla.components.feature.intent.processing.TabIntentProcessor 11 | import mozilla.components.feature.pwa.ManifestStorage 12 | import mozilla.components.feature.pwa.intent.WebAppIntentProcessor 13 | import mozilla.components.feature.search.SearchUseCases 14 | import mozilla.components.feature.session.SessionUseCases 15 | import mozilla.components.feature.tabs.CustomTabsUseCases 16 | import mozilla.components.feature.tabs.TabsUseCases 17 | import mozilla.components.lib.publicsuffixlist.PublicSuffixList 18 | 19 | /** 20 | * Component group for miscellaneous components. 21 | */ 22 | class Utilities( 23 | private val context: Context, 24 | private val store: BrowserStore, 25 | private val sessionUseCases: SessionUseCases, 26 | private val searchUseCases: SearchUseCases, 27 | private val tabsUseCases: TabsUseCases, 28 | private val customTabsUseCases: CustomTabsUseCases, 29 | ) { 30 | /** 31 | * Provides intent processing functionality for Progressive Web App and Custom Tab intents. 32 | */ 33 | val externalIntentProcessors by lazy { 34 | listOf( 35 | CustomTabIntentProcessor( 36 | customTabsUseCases.add, 37 | context.resources, 38 | ), 39 | WebAppIntentProcessor( 40 | store, 41 | customTabsUseCases.addWebApp, 42 | sessionUseCases.loadUrl, 43 | ManifestStorage(context), 44 | ), 45 | ) 46 | } 47 | 48 | /** 49 | * Provides intent processing functionality for ACTION_VIEW and ACTION_SEND intents, 50 | * along with external intent processors. 51 | */ 52 | val intentProcessors by lazy { 53 | externalIntentProcessors + 54 | TabIntentProcessor(tabsUseCases, searchUseCases.newTabSearch) 55 | } 56 | 57 | val publicSuffixList by lazy { 58 | PublicSuffixList(context) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/compose/ComposableComponents.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.compose 6 | 7 | import androidx.compose.runtime.Composable 8 | import androidx.compose.ui.platform.LocalContext 9 | import mozilla.components.browser.state.store.BrowserStore 10 | import mozilla.components.feature.session.SessionUseCases 11 | import org.mozilla.reference.browser.ext.components 12 | 13 | /** 14 | * Composable helper for providing the [BrowserStore] instance of this application. 15 | */ 16 | @Composable 17 | fun browserStore(): BrowserStore = LocalContext.current.components.core.store 18 | 19 | @Composable 20 | fun sessionUseCases(): SessionUseCases = LocalContext.current.components.useCases.sessionUseCases 21 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/customtabs/CustomTabsService.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.customtabs 6 | 7 | import mozilla.components.concept.engine.Engine 8 | import mozilla.components.feature.customtabs.AbstractCustomTabsService 9 | import mozilla.components.feature.customtabs.store.CustomTabsServiceStore 10 | import org.mozilla.reference.browser.ext.components 11 | 12 | class CustomTabsService : AbstractCustomTabsService() { 13 | override val customTabsServiceStore: CustomTabsServiceStore by lazy { components.core.customTabsStore } 14 | override val engine: Engine by lazy { components.core.engine } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/downloads/DownloadService.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.downloads 6 | 7 | import mozilla.components.browser.state.store.BrowserStore 8 | import mozilla.components.feature.downloads.AbstractFetchDownloadService 9 | import mozilla.components.feature.downloads.DateTimeProvider 10 | import mozilla.components.feature.downloads.FileSizeFormatter 11 | import mozilla.components.support.base.android.NotificationsDelegate 12 | import org.mozilla.reference.browser.ext.components 13 | 14 | class DownloadService : AbstractFetchDownloadService() { 15 | override val httpClient by lazy { components.core.client } 16 | override val store: BrowserStore by lazy { components.core.store } 17 | override val notificationsDelegate: NotificationsDelegate by lazy { components.notificationsDelegate } 18 | override val fileSizeFormatter: FileSizeFormatter by lazy { components.fileSizeFormatter } 19 | override val dateTimeProvider: DateTimeProvider by lazy { components.dateTimeProvider } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/ext/Context.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.ext 6 | 7 | import android.content.ActivityNotFoundException 8 | import android.content.Context 9 | import android.content.Intent 10 | import android.content.Intent.ACTION_SEND 11 | import android.content.Intent.EXTRA_SUBJECT 12 | import android.content.Intent.EXTRA_TEXT 13 | import android.content.Intent.FLAG_ACTIVITY_NEW_TASK 14 | import androidx.annotation.StringRes 15 | import mozilla.components.support.base.log.Log 16 | import mozilla.components.support.base.log.Log.Priority.WARN 17 | import org.mozilla.reference.browser.BrowserApplication 18 | import org.mozilla.reference.browser.Components 19 | import org.mozilla.reference.browser.R 20 | 21 | /** 22 | * Get the BrowserApplication object from a context. 23 | */ 24 | val Context.application: BrowserApplication 25 | get() = applicationContext as BrowserApplication 26 | 27 | /** 28 | * Get the requireComponents of this application. 29 | */ 30 | val Context.components: Components 31 | get() = application.components 32 | 33 | fun Context.getPreferenceKey( 34 | @StringRes resourceId: Int, 35 | ): String = resources.getString(resourceId) 36 | 37 | /** 38 | * Shares content via [ACTION_SEND] intent. 39 | * 40 | * @param text the data to be shared [EXTRA_TEXT] 41 | * @param subject of the intent [EXTRA_TEXT] 42 | * @return true it is able to share false otherwise. 43 | */ 44 | fun Context.share( 45 | text: String, 46 | subject: String = "", 47 | ): Boolean = 48 | try { 49 | val intent = Intent(ACTION_SEND).apply { 50 | type = "text/plain" 51 | putExtra(EXTRA_SUBJECT, subject) 52 | putExtra(EXTRA_TEXT, text) 53 | flags = FLAG_ACTIVITY_NEW_TASK 54 | } 55 | 56 | val shareIntent = Intent.createChooser(intent, getString(R.string.menu_share_with)).apply { 57 | flags = FLAG_ACTIVITY_NEW_TASK 58 | } 59 | 60 | startActivity(shareIntent) 61 | true 62 | } catch (e: ActivityNotFoundException) { 63 | Log.log(WARN, message = "No activity to share to found", throwable = e, tag = "Reference-Browser") 64 | false 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/ext/Fragment.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.ext 6 | 7 | import org.mozilla.reference.browser.Components 8 | 9 | /** 10 | * Get the requireComponents of this application. 11 | */ 12 | val androidx.fragment.app.Fragment.requireComponents: Components 13 | get() = requireContext().components 14 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/ext/Long.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.ext 6 | 7 | import android.content.Context 8 | import android.text.format.DateUtils 9 | import org.mozilla.reference.browser.R 10 | import java.util.Calendar 11 | import java.util.Date 12 | import java.util.GregorianCalendar 13 | 14 | @Suppress("MagicNumber") 15 | fun Long.timeSince( 16 | context: Context, 17 | time: Long, 18 | ): String { 19 | val earliestValidSyncDate: Date = GregorianCalendar.getInstance().run { 20 | set(2000, Calendar.JANUARY, 1, 0, 0, 0) 21 | getTime() 22 | } 23 | 24 | if (Date(time).before(earliestValidSyncDate)) { 25 | return context.getString(R.string.preferences_sync_never_synced_summary) 26 | } 27 | 28 | val relativeTimeSpanString = DateUtils.getRelativeTimeSpanString(time, this, DateUtils.MINUTE_IN_MILLIS) 29 | return context.resources.getString(R.string.preferences_sync_last_synced_summary, relativeTimeSpanString) 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/ext/String.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.ext 6 | 7 | /** 8 | * Replaces the keys with the values with the map provided. 9 | */ 10 | fun String.replace(pairs: Map): String { 11 | var result = this 12 | pairs.forEach { (l, r) -> result = result.replace(l, r) } 13 | return result 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/media/MediaSessionService.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.media 6 | 7 | import mozilla.components.browser.state.store.BrowserStore 8 | import mozilla.components.concept.base.crash.CrashReporting 9 | import mozilla.components.feature.media.service.AbstractMediaSessionService 10 | import mozilla.components.support.base.android.NotificationsDelegate 11 | import org.mozilla.reference.browser.ext.components 12 | 13 | /** 14 | * [AbstractMediaSessionService] implementation for injecting [BrowserStore] singleton. 15 | */ 16 | class MediaSessionService : AbstractMediaSessionService() { 17 | override val store: BrowserStore by lazy { components.core.store } 18 | override val crashReporter: CrashReporting by lazy { components.analytics.crashReporter } 19 | override val notificationsDelegate: NotificationsDelegate by lazy { components.notificationsDelegate } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/pip/PictureInPictureIntegration.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.pip 6 | 7 | import android.app.Activity 8 | import kotlinx.coroutines.CoroutineScope 9 | import kotlinx.coroutines.cancel 10 | import kotlinx.coroutines.flow.distinctUntilChangedBy 11 | import kotlinx.coroutines.flow.mapNotNull 12 | import mozilla.components.browser.state.selector.findTabOrCustomTabOrSelectedTab 13 | import mozilla.components.browser.state.store.BrowserStore 14 | import mozilla.components.feature.session.PictureInPictureFeature 15 | import mozilla.components.lib.state.ext.flowScoped 16 | import mozilla.components.support.base.feature.LifecycleAwareFeature 17 | 18 | class PictureInPictureIntegration( 19 | private val store: BrowserStore, 20 | activity: Activity, 21 | private val customTabId: String?, 22 | private val whiteList: List = listOf("youtube.com/tv"), 23 | ) : LifecycleAwareFeature { 24 | private var scope: CoroutineScope? = null 25 | private val pictureFeature = PictureInPictureFeature(store, activity) 26 | private var whiteListed = false 27 | 28 | override fun start() { 29 | scope = store.flowScoped { flow -> 30 | flow 31 | .mapNotNull { state -> state.findTabOrCustomTabOrSelectedTab(customTabId) } 32 | .distinctUntilChangedBy { it.content.url } 33 | .collect { whiteListed = isWhitelisted(it.content.url) } 34 | } 35 | } 36 | 37 | override fun stop() { 38 | scope?.cancel() 39 | } 40 | 41 | fun onHomePressed() = 42 | if (whiteListed) { 43 | pictureFeature.enterPipModeCompat() 44 | } else { 45 | pictureFeature.onHomePressed() 46 | } 47 | 48 | private fun isWhitelisted(url: String): Boolean { 49 | val exists = whiteList.firstOrNull { url.contains(it) } 50 | return exists != null 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/push/FirebasePush.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.push 6 | 7 | import android.annotation.SuppressLint 8 | import mozilla.components.lib.push.firebase.AbstractFirebasePushService 9 | 10 | @SuppressLint("MissingFirebaseInstanceTokenRefresh") 11 | class FirebasePush : AbstractFirebasePushService() 12 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/settings/Settings.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.settings 6 | 7 | import android.content.Context 8 | import androidx.core.content.edit 9 | import androidx.preference.PreferenceManager 10 | import org.mozilla.reference.browser.R 11 | 12 | object Settings { 13 | fun isTelemetryEnabled(context: Context): Boolean = 14 | PreferenceManager.getDefaultSharedPreferences(context).getBoolean( 15 | context.getString(R.string.pref_key_telemetry), 16 | true, 17 | ) 18 | 19 | fun getOverrideAmoUser(context: Context): String = 20 | PreferenceManager.getDefaultSharedPreferences(context).getString( 21 | context.getString(R.string.pref_key_override_amo_user), 22 | "", 23 | ) ?: "" 24 | 25 | fun getOverrideAmoCollection(context: Context): String = 26 | PreferenceManager.getDefaultSharedPreferences(context).getString( 27 | context.getString(R.string.pref_key_override_amo_collection), 28 | "", 29 | ) ?: "" 30 | 31 | fun setOverrideAmoUser( 32 | context: Context, 33 | value: String, 34 | ) { 35 | val key = context.getString(R.string.pref_key_override_amo_user) 36 | PreferenceManager.getDefaultSharedPreferences(context).edit { 37 | putString(key, value) 38 | } 39 | } 40 | 41 | fun setOverrideAmoCollection( 42 | context: Context, 43 | value: String, 44 | ) { 45 | val key = context.getString(R.string.pref_key_override_amo_collection) 46 | PreferenceManager.getDefaultSharedPreferences(context).edit { 47 | putString(key, value) 48 | } 49 | } 50 | 51 | fun isAmoCollectionOverrideConfigured(context: Context): Boolean = 52 | getOverrideAmoUser(context).isNotEmpty() && getOverrideAmoCollection(context).isNotEmpty() 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/settings/SettingsActivity.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.settings 6 | 7 | import android.R.id.content 8 | import android.os.Bundle 9 | import android.view.MenuItem 10 | import androidx.appcompat.app.AppCompatActivity 11 | import mozilla.components.support.base.feature.UserInteractionHandler 12 | 13 | class SettingsActivity : 14 | AppCompatActivity(), 15 | SettingsFragment.ActionBarUpdater { 16 | override fun onCreate(savedInstanceState: Bundle?) { 17 | super.onCreate(savedInstanceState) 18 | 19 | if (savedInstanceState == null) { 20 | with(supportFragmentManager.beginTransaction()) { 21 | replace(content, SettingsFragment()) 22 | commit() 23 | } 24 | } 25 | } 26 | 27 | override fun onOptionsItemSelected(item: MenuItem): Boolean = 28 | when (item.itemId) { 29 | android.R.id.home -> { 30 | onBackPressedDispatcher.onBackPressed() 31 | true 32 | } 33 | else -> super.onOptionsItemSelected(item) 34 | } 35 | 36 | override fun updateTitle(titleResId: Int) { 37 | setTitle(titleResId) 38 | } 39 | 40 | @Suppress("MissingSuperCall", "OVERRIDE_DEPRECATION") 41 | override fun onBackPressed() { 42 | supportFragmentManager.fragments.forEach { 43 | if (it is UserInteractionHandler && it.onBackPressed()) { 44 | return 45 | } else { 46 | super.onBackPressedDispatcher.onBackPressed() 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/sync/BrowserFxAEntryPoint.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.sync 6 | 7 | import mozilla.components.concept.sync.FxAEntryPoint 8 | 9 | /** 10 | * Reference Browser implementation of [FxAEntryPoint]. 11 | */ 12 | enum class BrowserFxAEntryPoint( 13 | override val entryName: String, 14 | ) : FxAEntryPoint { 15 | /** 16 | * Authenticating from the home menu (the hamburger menu) 17 | */ 18 | HomeMenu("home-menu"), 19 | 20 | /** 21 | * Authenticating from the account settings 22 | */ 23 | AccountSettings("account-settings"), 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/tabs/LastTabFeature.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.tabs 6 | 7 | import android.app.Activity 8 | import mozilla.components.browser.state.selector.findTabOrCustomTabOrSelectedTab 9 | import mozilla.components.browser.state.state.SessionState 10 | import mozilla.components.browser.state.state.TabSessionState 11 | import mozilla.components.browser.state.store.BrowserStore 12 | import mozilla.components.feature.tabs.TabsUseCases 13 | import mozilla.components.support.base.feature.LifecycleAwareFeature 14 | import mozilla.components.support.base.feature.UserInteractionHandler 15 | 16 | /** 17 | * A feature that removes the tab and selects the parent, if one exists. 18 | */ 19 | class LastTabFeature( 20 | private val store: BrowserStore, 21 | private val tabId: String? = null, 22 | private val removeTabUseCase: TabsUseCases.RemoveTabUseCase, 23 | private val activity: Activity, 24 | ) : LifecycleAwareFeature, 25 | UserInteractionHandler { 26 | override fun start() = Unit 27 | 28 | override fun stop() = Unit 29 | 30 | /** 31 | * Removes the session if it was opened by an ACTION_VIEW intent 32 | * or if it has a parent session and no more history. 33 | */ 34 | override fun onBackPressed(): Boolean { 35 | val tab = store.state.findTabOrCustomTabOrSelectedTab(tabId) ?: return false 36 | val isExternalOrCustomTab = tab.source is SessionState.Source.External || 37 | tab.source is SessionState.Source.Internal.CustomTab 38 | 39 | return if (isExternalOrCustomTab && !tab.restored) { 40 | activity.finish() 41 | removeTabUseCase(tab.id) 42 | true 43 | } else { 44 | val hasParent = tab is TabSessionState && tab.parentId != null 45 | removeTabUseCase(tab.id, selectParentIfExists = hasParent) // Alternatively, set this to always true. 46 | // We want to return to home if this session didn't have a parent session to select. 47 | hasParent 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/tabs/PrivatePage.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.tabs 6 | 7 | import android.content.Context 8 | import androidx.annotation.RawRes 9 | import org.mozilla.reference.browser.R 10 | 11 | object PrivatePage { 12 | /** 13 | * Load and generate a private browsing page for the given url and html/css resources 14 | */ 15 | fun createPrivateBrowsingPage( 16 | context: Context, 17 | url: String, 18 | @RawRes htmlRes: Int = R.raw.private_mode, 19 | @RawRes cssRes: Int = R.raw.private_style, 20 | ): String { 21 | val css = context.resources.openRawResource(cssRes).bufferedReader().use { 22 | it.readText() 23 | } 24 | 25 | return context.resources 26 | .openRawResource(htmlRes) 27 | .bufferedReader() 28 | .use { it.readText() } 29 | .replace("%pageTitle%", context.getString(R.string.private_browsing_title)) 30 | .replace("%pageBody%", context.getString(R.string.private_browsing_body)) 31 | .replace("%privateBrowsingSupportUrl%", url) 32 | .replace("%css%", css) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/tabs/TabsTouchHelper.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.tabs 6 | 7 | import androidx.recyclerview.widget.ItemTouchHelper 8 | import mozilla.components.browser.state.state.TabSessionState 9 | import mozilla.components.browser.tabstray.TabTouchCallback 10 | import kotlin.math.abs 11 | 12 | class TabsTouchHelper( 13 | observable: (TabSessionState) -> Unit, 14 | ) : ItemTouchHelper(object : TabTouchCallback(observable) { 15 | override fun alphaForItemSwipe( 16 | dX: Float, 17 | distanceToAlphaMin: Int, 18 | ): Float = 1f - 2f * abs(dX) / distanceToAlphaMin 19 | }) 20 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/tabs/synced/SyncedTabsActivity.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.tabs.synced 6 | 7 | import android.os.Bundle 8 | import androidx.appcompat.app.AppCompatActivity 9 | import org.mozilla.reference.browser.R 10 | 11 | class SyncedTabsActivity : AppCompatActivity() { 12 | override fun onCreate(savedInstanceState: Bundle?) { 13 | super.onCreate(savedInstanceState) 14 | setContentView(R.layout.activity_main) 15 | 16 | if (savedInstanceState == null) { 17 | supportFragmentManager.beginTransaction().apply { 18 | replace( 19 | R.id.container, 20 | SyncedTabsFragment(), 21 | ) 22 | commit() 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/tabs/synced/SyncedTabsFragment.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.tabs.synced 6 | 7 | import android.content.Intent 8 | import android.os.Bundle 9 | import android.view.LayoutInflater 10 | import android.view.View 11 | import android.view.ViewGroup 12 | import androidx.core.net.toUri 13 | import androidx.fragment.app.Fragment 14 | import mozilla.components.browser.storage.sync.Tab 15 | import mozilla.components.feature.syncedtabs.SyncedTabsFeature 16 | import mozilla.components.support.base.feature.ViewBoundFeatureWrapper 17 | import org.mozilla.reference.browser.R 18 | import org.mozilla.reference.browser.ext.components 19 | 20 | class SyncedTabsFragment : Fragment() { 21 | private val syncedTabsFeature = ViewBoundFeatureWrapper() 22 | 23 | override fun onCreateView( 24 | inflater: LayoutInflater, 25 | container: ViewGroup?, 26 | savedInstanceState: Bundle?, 27 | ): View? = inflater.inflate(R.layout.fragment_synced_tabs, container, false) 28 | 29 | override fun onViewCreated( 30 | view: View, 31 | savedInstanceState: Bundle?, 32 | ) { 33 | super.onViewCreated(view, savedInstanceState) 34 | 35 | val backgroundServices = requireContext().components.backgroundServices 36 | 37 | syncedTabsFeature.set( 38 | feature = SyncedTabsFeature( 39 | context = requireContext(), 40 | storage = backgroundServices.syncedTabsStorage, 41 | commands = backgroundServices.syncedTabsCommands, 42 | accountManager = backgroundServices.accountManager, 43 | view = view.findViewById(R.id.synced_tabs_layout), 44 | lifecycleOwner = this, 45 | onTabClicked = ::handleTabClicked, 46 | ), 47 | owner = this, 48 | view = view, 49 | ) 50 | } 51 | 52 | private fun handleTabClicked(tab: Tab) { 53 | val browserIntent = Intent(Intent.ACTION_VIEW, tab.active().url.toUri()) 54 | requireContext().startActivity(browserIntent) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/org/mozilla/reference/browser/tabs/synced/SyncedTabsIntegration.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | package org.mozilla.reference.browser.tabs.synced 6 | 7 | import android.content.Context 8 | import androidx.lifecycle.ProcessLifecycleOwner 9 | import mozilla.components.concept.sync.AccountObserver 10 | import mozilla.components.concept.sync.AuthType 11 | import mozilla.components.concept.sync.OAuthAccount 12 | import mozilla.components.service.fxa.manager.FxaAccountManager 13 | import org.mozilla.reference.browser.ext.components 14 | 15 | class SyncedTabsIntegration( 16 | private val context: Context, 17 | private val accountManager: FxaAccountManager, 18 | ) { 19 | fun launch() { 20 | val accountObserver = SyncedTabsAccountObserver(context) 21 | 22 | accountManager.register( 23 | accountObserver, 24 | owner = ProcessLifecycleOwner.get(), 25 | autoPause = true, 26 | ) 27 | } 28 | } 29 | 30 | internal class SyncedTabsAccountObserver( 31 | private val context: Context, 32 | ) : AccountObserver { 33 | override fun onAuthenticated( 34 | account: OAuthAccount, 35 | authType: AuthType, 36 | ) { 37 | context.components.backgroundServices.syncedTabsStorage 38 | .start() 39 | } 40 | 41 | override fun onLoggedOut() { 42 | context.components.backgroundServices.syncedTabsStorage 43 | .stop() 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/main/res/drawable-hdpi/ic_notification.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/main/res/drawable-mdpi/ic_notification.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/main/res/drawable-xhdpi/ic_notification.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/main/res/drawable-xxhdpi/ic_notification.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/main/res/drawable-xxxhdpi/ic_notification.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/addon_textview_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_icon_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/mozac_ic_extensions_black.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 10 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/mozac_ic_permissions.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 11 | 14 | 17 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/url_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_add_on_permissions.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 13 | 17 | 18 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_add_on_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/add_ons_permission_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 15 | 16 | 24 | 25 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/layout/amo_collection_override_dialog.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 10 | 11 | 22 | 23 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_about.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 13 | 14 | 24 | 25 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_add_on_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | 12 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_add_ons.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | 12 | 17 | 18 | 19 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_pairing.xml: -------------------------------------------------------------------------------- 1 | 4 | 7 | 8 | 12 | 13 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_synced_tabs.xml: -------------------------------------------------------------------------------- 1 | 4 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_tabstray.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 9 | 10 | 17 | 18 | 19 | 27 | 28 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_synced_tabs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 10 | 11 | 17 | 18 | 22 | 23 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/layout/overlay_add_on_progress.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | 12 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/layout/preference_autofill.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/view_synced_tabs_group.xml: -------------------------------------------------------------------------------- 1 | 4 | 13 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/layout/view_synced_tabs_item.xml: -------------------------------------------------------------------------------- 1 | 4 | 16 | 17 | 26 | 27 | 37 | 38 | 49 | 50 | -------------------------------------------------------------------------------- /app/src/main/res/menu/tabstray_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 7 | 12 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_icon_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/main/res/mipmap-hdpi/ic_icon_background.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_icon_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/main/res/mipmap-mdpi/ic_icon_background.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_icon_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/main/res/mipmap-xhdpi/ic_icon_background.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_icon_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/main/res/mipmap-xxhdpi/ic_icon_background.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_icon_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/main/res/mipmap-xxxhdpi/ic_icon_background.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/raw/private_mode.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | %pageTitle% 11 | 12 | 13 | 14 | 15 | 16 | 17 | icon-private-browsing 18 | 19 | 20 | 21 |
22 | 23 |
%pageBody%
24 |
25 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | #ff212121 7 | #ff1a1a1a 8 | #ff00BCD4 9 | 10 | @color/evenDarker 11 | #333333 12 | 13 | #ffffffff 14 | 15 | 16 | @color/icons 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 56dp 8 | -------------------------------------------------------------------------------- /app/src/main/res/values/preference_keys.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | pref_key_autofill 7 | pref_key_sign_in 8 | pref_key_pair_sign_in 9 | pref_key_sign_out 10 | pref_key_sync_now 11 | pref_key_sync_manage_account 12 | pref_key_firefox_account 13 | pref_key_telemetry 14 | pref_key_make_default_browser 15 | pref_key_sync_history 16 | pref_key_sync_tabs 17 | pref_key_sync_passwords 18 | pref_key_remote_debugging 19 | pref_key_testing_mode 20 | pref_key_about_page 21 | pref_key_privacy 22 | pref_key_tracking_protection_normal 23 | pref_key_tracking_protection_private 24 | pref_key_global_privacy_control 25 | pref_key_launch_external_app 26 | pref_key_override_amo_collection 27 | pref_key_override_amo_user 28 | pref_key_compose_ui 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/values/style.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/xml/account_preferences.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | 9 | 13 | 14 | 17 | 18 | 21 | 22 | 24 | 25 | 30 | 31 | 36 | 37 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/res/xml/backup_rules.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/xml/data_extraction_rules.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/xml/privacy_preferences.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | 9 | 11 | 12 | 16 | 17 | 21 | 22 | 23 | 24 | 28 | 29 | 31 | 32 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /automation/gradle/versionCode.gradle: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | import java.text.SimpleDateFormat 6 | 7 | // This gradle scripts generates a "unique" version code for our release versions. 8 | // 9 | // The result of the version code depends on the timezone. We assume that this script will only be used 10 | // for release versions and running on our build servers with a fixed timezone. 11 | // 12 | // The version code is composed like: yDDDHHmm 13 | // * y = Double digit year, with 18 subtracted: 2018 -> 18 -> 0 14 | // * DDD = Day of the year, pad with zeros if needed: September 6th -> 249 15 | // * HH = Hour in day (00-23) 16 | // * mm = Minute in hour 17 | // 18 | // For September 6th, 2018, 9:41 am this will generate the versionCode: 2490941 (0-249-09-41). 19 | // 20 | // Note that we only use this generated version code for builds we want to distribute. For local 21 | // debug builds we use a fixed versionCode to not mess with the caching mechanism of the build 22 | // system. 23 | 24 | ext { 25 | def today = new Date() 26 | 27 | // We use the current year (double digit) and subtract 18. We first released Reference Browser in 28 | // 2018 so this value will start counting at 0 and increment by one every year. 29 | def year = String.valueOf((new SimpleDateFormat("yy").format(today) as int) - 18) 30 | 31 | // We use the day in the Year (e.g. 248) as opposed to month + day (0510) because it's one digit shorter. 32 | // If needed we pad with zeros (e.g. 25 -> 025) 33 | def day = String.format("%03d", (new SimpleDateFormat("D").format(today) as int)) 34 | 35 | // We append the hour in day (24h) and minute in hour (7:26 pm -> 1926). We do not append 36 | // seconds. This assumes that we do not need to build multiple release(!) builds the same 37 | // minute. 38 | def time = new SimpleDateFormat("HHmm").format(today) 39 | 40 | generatedVersionCode = (year + day + time) as int 41 | 42 | println("Generated versionCode: $generatedVersionCode") 43 | println() 44 | } 45 | -------------------------------------------------------------------------------- /automation/taskcluster/androidTest/flank-arm64-v8a.yml: -------------------------------------------------------------------------------- 1 | # Google Cloud Documentation: https://cloud.google.com/sdk/gcloud/reference/firebase/test/android/run 2 | # Flank Documentation: https://flank.github.io/flank/ 3 | gcloud: 4 | results-bucket: reference-browser_test_artifacts 5 | record-video: true 6 | 7 | timeout: 30m 8 | async: false 9 | num-flaky-test-attempts: 1 10 | 11 | app: /app/path 12 | test: /test/path 13 | 14 | auto-google-login: false 15 | use-orchestrator: true 16 | environment-variables: 17 | clearPackageData: true 18 | directories-to-pull: 19 | - /sdcard/screenshots 20 | performance-metrics: true 21 | 22 | test-targets: 23 | - package org.mozilla.reference.browser.ui 24 | 25 | device: 26 | - model: MediumPhone.arm 27 | version: 30 28 | locale: en_US 29 | 30 | flank: 31 | project: GOOGLE_PROJECT 32 | max-test-shards: 50 33 | num-test-runs: 1 34 | output-style: compact 35 | full-junit-result: true 36 | -------------------------------------------------------------------------------- /automation/taskcluster/androidTest/flank-x86.yml: -------------------------------------------------------------------------------- 1 | # Google Cloud Documentation: https://cloud.google.com/sdk/gcloud/reference/firebase/test/android/run 2 | # Flank Documentation: https://flank.github.io/flank/ 3 | gcloud: 4 | results-bucket: reference-browser_test_artifacts 5 | record-video: true 6 | 7 | timeout: 30m 8 | async: false 9 | num-flaky-test-attempts: 1 10 | 11 | app: /app/path 12 | test: /test/path 13 | 14 | auto-google-login: false 15 | use-orchestrator: true 16 | environment-variables: 17 | clearPackageData: true 18 | directories-to-pull: 19 | - /sdcard/screenshots 20 | performance-metrics: true 21 | 22 | test-targets: 23 | - package org.mozilla.reference.browser.ui 24 | 25 | device: 26 | - model: Pixel2 27 | version: 30 28 | locale: en_US 29 | 30 | flank: 31 | project: GOOGLE_PROJECT 32 | max-test-shards: 50 33 | num-test-runs: 1 34 | output-style: compact 35 | full-junit-result: true 36 | -------------------------------------------------------------------------------- /buildSrc/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | plugins { 6 | `kotlin-dsl-base` 7 | } 8 | 9 | repositories { 10 | mavenCentral() 11 | } 12 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/Config.kt: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | import org.gradle.api.Project 6 | import java.text.SimpleDateFormat 7 | import java.util.Date 8 | import java.util.Locale 9 | 10 | object Config { 11 | // Synchronized build configuration for all modules 12 | const val compileSdkVersion = 36 13 | const val minSdkVersion = 21 14 | const val targetSdkVersion = 36 15 | const val jvmTargetCompatibility = 17 16 | 17 | @JvmStatic 18 | fun generateDebugVersionName(): String { 19 | val today = Date() 20 | // Append the year (2 digits) and week in year (2 digits). This will make it easier to distinguish versions and 21 | // identify ancient versions when debugging issues. However this will still keep the same version number during 22 | // the week so that we do not end up with a lot of versions in tools like Sentry. As an extra this matches the 23 | // sections we use in the changelog (weeks). 24 | return SimpleDateFormat("1.0.yyww", Locale.US).format(today) 25 | } 26 | 27 | @JvmStatic 28 | fun releaseVersionName(project: Project): String { 29 | // This function is called in the configuration phase, before gradle knows which variants we'll use. 30 | // So, validation that "versionName" has been set happens elsewhere (at time of writing, we staple 31 | // validation to tasks of type "AppPreBuildTask" 32 | return if (project.hasProperty("versionName")) project.property("versionName") as String else "" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /certificates/nightly.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDyTCCArGgAwIBAgIEYubfuDANBgkqhkiG9w0BAQsFADCBlDELMAkGA1UEBhMC 3 | VVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcx 4 | HDAaBgNVBAoTE01vemlsbGEgQ29ycG9yYXRpb24xHDAaBgNVBAsTE1JlbGVhc2Ug 5 | RW5naW5lZXJpbmcxHDAaBgNVBAMTE1JlbGVhc2UgRW5naW5lZXJpbmcwHhcNMTgx 6 | MTI2MDY0NzUwWhcNNDYwNDEzMDY0NzUwWjCBlDELMAkGA1UEBhMCVVMxEzARBgNV 7 | BAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxHDAaBgNVBAoT 8 | E01vemlsbGEgQ29ycG9yYXRpb24xHDAaBgNVBAsTE1JlbGVhc2UgRW5naW5lZXJp 9 | bmcxHDAaBgNVBAMTE1JlbGVhc2UgRW5naW5lZXJpbmcwggEiMA0GCSqGSIb3DQEB 10 | AQUAA4IBDwAwggEKAoIBAQCgaIPBpFfm32lrwu/hvHbEhANwAG1Bx3ve+kys2uqk 11 | 2E/CnuOZ7Igzwj2Gs00AdiGazcLrTnhFQPItR5McYd+yxvz9KkFvN6lcsAoN2IQx 12 | qe5tNMd7/XmYACG2PEDCokyNpJ8BX1r62TIc0qklr1P06nyraY9A9d0wCgYD/3s8 13 | gXPlHEf86Ba/194Vo/+LDIdbyA6Z854064ef4d6j6gCmqzAFQig1JXJJV5TGy9wC 14 | UqtI9S9HzlOPufLIZQujvhQFB7AahtIvVCbLeDfKV23s4FZfvEzqNQkxQ2T6p6JX 15 | EfbWY3QzEGge473G1dG0PbJy181dbxlw+UISiQXY9c5tAgMBAAGjITAfMB0GA1Ud 16 | DgQWBBReLaZaWOJg+EGGL3unx9Hs1sqEDDANBgkqhkiG9w0BAQsFAAOCAQEAhuul 17 | /zU3q1enbfY0srcTGyRIsLo7FhWU3OY0CINf+AYe9K3vRIaZ4GoLxUc8e2AkYcOt 18 | FPHKk+lAQQFwEYLJWcgb98o4oU3VR0gsJ7vqyubxoLB7iO/aOwOUbWEL+ZZFo5KM 19 | eBK5SI5u1VqDXFfGVxyhwRRpA+n13CVh9xoHLX9EBwy6qXvEaJquuvOy05OdRTI2 20 | RkQZbwCH3/+c7T80Aq87UXXA3lS6lwiylb4/K7SKBRssYkI/a5LKMl7S20C3BuxD 21 | K23coFk9dO4XNqPp75jT0BemtFGgjJVA4DskgAAse6H+YDXDLac3U39udpDIeCdh 22 | pu/h9T3uqfuRY/nDYA== 23 | -----END CERTIFICATE----- 24 | -------------------------------------------------------------------------------- /certificates/raptor.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDvTCCAqWgAwIBAgIEQ1LLjTANBgkqhkiG9w0BAQsFADCBjjELMAkGA1UEBhMC 3 | VVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcx 4 | HDAaBgNVBAoTE01vemlsbGEgQ29ycG9yYXRpb24xHDAaBgNVBAsTE1JlbGVhc2Ug 5 | RW5naW5lZXJpbmcxFjAUBgNVBAMTDVRocm93YXdheSBLZXkwHhcNMTkwMTE1MTk0 6 | MTUwWhcNNDYwNjAyMTk0MTUwWjCBjjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNh 7 | bGlmb3JuaWExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxHDAaBgNVBAoTE01vemls 8 | bGEgQ29ycG9yYXRpb24xHDAaBgNVBAsTE1JlbGVhc2UgRW5naW5lZXJpbmcxFjAU 9 | BgNVBAMTDVRocm93YXdheSBLZXkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK 10 | AoIBAQChMIAu+j5WGMKgFxtxhJvrjsx54Sy3gwjn+YFjn1WcPuQHbxRCZO9ZqWIr 11 | +dvotcIJfJ0iRin7sCaFzCGUdfmEUoOofVwUyyWnnV0hnLSP39wG0wWdLWjsZSOZ 12 | YwVQlNMxG1WUmQjykmtYasq5E4PxZbMY0xBgDu/IXf5Cx5o3WHd/GE3wkmR3zTQQ 13 | nlbjW4M3MaVhTIe3+eS1uueCRBixWDMYyCVbEkWo1EaRHw/gUKElSGxvqnOqzrf0 14 | Ey9lF07+xtLXSwf3CG8TZACwzUOmUf+ONFpGEosTwBxPcDLFxxjqle7NJmD3EH4W 15 | MV3Swh1XSBv2/o2qFtXC/FpcBjevAgMBAAGjITAfMB0GA1UdDgQWBBQCyNV+Vbwf 16 | F4P/1/+nF8TUb6BbCjANBgkqhkiG9w0BAQsFAAOCAQEAQjnuheDT5aabSkECLtqv 17 | tq2NDIhhoyiVBi7SPP5wHrdXEByFThJUeJD2/P5urQCjF3Z+rPSVn2Jxxq7zc+0m 18 | /oBQCh5+8MsGwBxmetfv6w2QIIf/7xpsPAv7vxZo64HOWOs3yprR371e2gDSFvXE 19 | eDSIgEjXm7TPFWVryXrrHdi/ZszWB5dU0Y2bw4wlEDOguankI+ztYrUmOeSIDDIV 20 | eZHPMdpXlRqtHIrw4Z+dNWgmRMtFcSYjihsaQMhMp+3pudkvoxPpUo4vbV+yoy89 21 | OfEqSBiYPOa/+CuIgqbTT2PxdT7dSwqgNBzXqMPEz830dZ+XB7T+lTvVMqirntaw 22 | DQ== 23 | -----END CERTIFICATE----- 24 | -------------------------------------------------------------------------------- /config/license.template: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx4096m -XX:+HeapDumpOnOutOfMemoryError -XX:+UseParallelGC 13 | org.gradle.daemon=true 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | org.gradle.parallel=true 19 | 20 | # We want to use AndroidX. 21 | android.useAndroidX=true 22 | android.enableJetifier=true 23 | 24 | # Broken builds with AGP 8 25 | android.nonTransitiveRClass=false 26 | 27 | # Print dependency analysis results to the console 28 | dependency.analysis.print.build.health=true 29 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /l10n.toml: -------------------------------------------------------------------------------- 1 | 2 | basepath = "." 3 | 4 | locales = [ 5 | 6 | ] 7 | [env] 8 | 9 | [[paths]] 10 | reference = "app/src/main/res/values/strings.xml" 11 | l10n = "{l10n_base}/app/src/main/res/values-{android_locale}/strings.xml" 12 | 13 | -------------------------------------------------------------------------------- /taskcluster/config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | trust-domain: mobile 3 | treeherder: 4 | group-names: 5 | 'bump': 'Bump dependencies' 6 | 'debug': 'Builds made for testing' 7 | 'Fetch': 'Fetch and store content' 8 | 'I': 'Docker Image Builds' 9 | 'Rap': 'Raptor tests' 10 | 'Rap-P': 'Raptor power tests' 11 | 'TL': 'Toolchain builds for Linux 64-bits' 12 | 13 | task-priority: lowest 14 | 15 | taskgraph: 16 | register: rb_taskgraph:register 17 | repositories: 18 | mobile: 19 | name: "reference-browser" 20 | cached-task-prefix: mobile.v2.reference-browser 21 | 22 | workers: 23 | aliases: 24 | b-android: 25 | provisioner: 'mobile-{level}' 26 | implementation: docker-worker 27 | os: linux 28 | worker-type: 'b-linux-gcp' 29 | dep-signing: 30 | provisioner: scriptworker-k8s 31 | implementation: scriptworker-signing 32 | os: scriptworker 33 | worker-type: mobile-t-signing 34 | images: 35 | provisioner: 'mobile-{level}' 36 | implementation: docker-worker 37 | os: linux 38 | worker-type: 'images-gcp' 39 | misc: 40 | provisioner: 'mobile-{level}' 41 | implementation: docker-worker 42 | os: linux 43 | worker-type: 'b-linux-gcp' 44 | push-apk: 45 | provisioner: scriptworker-k8s 46 | implementation: scriptworker-pushapk 47 | os: scriptworker 48 | worker-type: 'mobile-{level}-pushapk' 49 | signing: 50 | provisioner: scriptworker-k8s 51 | implementation: scriptworker-signing 52 | os: scriptworker 53 | worker-type: 54 | by-level: 55 | "3": mobile-3-signing 56 | default: mobile-t-signing 57 | t-bitbar.*: 58 | provisioner: proj-autophone 59 | implementation: generic-worker 60 | os: linux-bitbar 61 | worker-type: 'gecko-{alias}' 62 | 63 | scriptworker: 64 | scope-prefix: project:mobile:reference-browser:releng 65 | -------------------------------------------------------------------------------- /taskcluster/docker/REGISTRY: -------------------------------------------------------------------------------- 1 | mozilla-mobile 2 | -------------------------------------------------------------------------------- /taskcluster/docker/android-build/Dockerfile: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | ARG DOCKER_IMAGE_PARENT 6 | FROM $DOCKER_IMAGE_PARENT 7 | 8 | MAINTAINER Johan Lorenzo 9 | 10 | VOLUME /builds/worker/checkouts 11 | 12 | # Install Java 8 needed for Nexus 13 | RUN apt-get update -qq \ 14 | && apt-get install -y openjdk-8-jdk \ 15 | && apt-get clean 16 | 17 | # Install Sonatype Nexus. Cribbed directly from 18 | # https://github.com/sonatype/docker-nexus/blob/0415e54b6c824d510f883e5a75c4008b936eca62/oss/Dockerfile. 19 | 20 | ENV NEXUS_ARCHIVE='nexus-bundle.tar.gz' \ 21 | NEXUS_ROOT='/opt/sonatype/nexus' \ 22 | NEXUS_SHA1SUM=0fcb4f002eec0cbad6b421b90a8fe99959d78e93 \ 23 | NEXUS_VERSION=2.15.1-02 \ 24 | NEXUS_WORK=/builds/worker/workspace/nexus 25 | 26 | RUN mkdir -p "$NEXUS_ROOT" \ 27 | && chown -R worker:worker "$NEXUS_ROOT" 28 | 29 | USER worker:worker 30 | 31 | RUN $CURL --output "$NEXUS_ARCHIVE" "https://download.sonatype.com/nexus/oss/nexus-${NEXUS_VERSION}-bundle.tar.gz" \ 32 | && echo "$NEXUS_SHA1SUM $NEXUS_ARCHIVE" | sha1sum --check \ 33 | && tar xzvf "$NEXUS_ARCHIVE" --strip-components=1 --directory="$NEXUS_ROOT" \ 34 | && rm "$NEXUS_ARCHIVE" 35 | 36 | # run-task expects to run as root 37 | USER root 38 | -------------------------------------------------------------------------------- /taskcluster/docker/base/Dockerfile: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | FROM ubuntu:22.04 6 | 7 | MAINTAINER Tom Prince "mozilla@hocat.ca" 8 | 9 | # Add worker user 10 | RUN mkdir -p /builds && \ 11 | useradd -d /builds/worker -s /bin/bash -m worker && \ 12 | chown worker:worker /builds/worker && \ 13 | mkdir /builds/worker/artifacts && \ 14 | chown worker:worker /builds/worker/artifacts 15 | 16 | WORKDIR /builds/worker/ 17 | 18 | #---------------------------------------------------------------------------------------------------------------------- 19 | #-- Configuration ----------------------------------------------------------------------------------------------------- 20 | #---------------------------------------------------------------------------------------------------------------------- 21 | 22 | ENV CURL='curl --location --retry 5' \ 23 | GRADLE_OPTS='-Xmx4096m -Dorg.gradle.daemon=false' \ 24 | LANG='en_US.UTF-8' \ 25 | TERM='dumb' 26 | 27 | #---------------------------------------------------------------------------------------------------------------------- 28 | #-- System ------------------------------------------------------------------------------------------------------------ 29 | #---------------------------------------------------------------------------------------------------------------------- 30 | 31 | RUN apt-get update -qq \ 32 | # We need to install tzdata before all of the other packages. Otherwise it will show an interactive dialog that 33 | # we cannot navigate while building the Docker image. 34 | && apt-get install -y tzdata \ 35 | && apt-get install -y openjdk-17-jdk \ 36 | wget \ 37 | expect \ 38 | git \ 39 | curl \ 40 | python3 \ 41 | python3-pip \ 42 | locales \ 43 | unzip \ 44 | mercurial \ 45 | && apt-get clean 46 | 47 | RUN pip3 install --upgrade pip 48 | RUN pip3 install taskcluster 49 | 50 | RUN locale-gen "$LANG" 51 | 52 | 53 | # %include-run-task 54 | 55 | ENV SHELL=/bin/bash \ 56 | HOME=/builds/worker \ 57 | PATH="/builds/worker/.local/bin:$PATH" 58 | 59 | 60 | VOLUME /builds/worker/checkouts 61 | VOLUME /builds/worker/.cache 62 | 63 | 64 | # run-task expects to run as root 65 | USER root 66 | -------------------------------------------------------------------------------- /taskcluster/docker/bump/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG DOCKER_IMAGE_PARENT 2 | FROM $DOCKER_IMAGE_PARENT 3 | 4 | MAINTAINER Johan Lorenzo 5 | 6 | USER worker:worker 7 | 8 | ENV HUB_ARCHIVE='hub.tgz' \ 9 | HUB_ROOT='/builds/worker/hub' \ 10 | HUB_SHA256='734733c9d807715a4ec26ccce0f9987bd19f1c3f84dd35e56451711766930ef0' \ 11 | HUB_VERSION='2.14.1' 12 | 13 | RUN $CURL --output "$HUB_ARCHIVE" "https://github.com/github/hub/releases/download/v$HUB_VERSION/hub-linux-amd64-$HUB_VERSION.tgz" \ 14 | && echo "$HUB_SHA256 $HUB_ARCHIVE" | sha256sum --check \ 15 | && mkdir -p "$HUB_ROOT" \ 16 | && tar xzvf "$HUB_ARCHIVE" --strip-components=1 --directory="$HUB_ROOT" \ 17 | && rm "$HUB_ARCHIVE" 18 | 19 | ENV PATH="$HUB_ROOT/bin:$PATH" 20 | 21 | COPY mozilla_key.asc owner_trust.db ./ 22 | RUN gpg --import mozilla_key.asc \ 23 | && gpg --import-ownertrust owner_trust.db \ 24 | && rm mozilla_key.asc owner_trust.db 25 | 26 | # run-task expects to run as root 27 | USER root 28 | -------------------------------------------------------------------------------- /taskcluster/docker/bump/owner_trust.db: -------------------------------------------------------------------------------- 1 | # List of assigned trustvalues 2 | # (Use "gpg --import-ownertrust" to restore them) 3 | 14F26682D0916CDD81E37B6D61B7B526D98F0353:6: 4 | -------------------------------------------------------------------------------- /taskcluster/docker/ui-tests/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG DOCKER_IMAGE_PARENT 2 | FROM $DOCKER_IMAGE_PARENT 3 | 4 | LABEL authors="Richard Pappalardo , Aaron Train " 5 | LABEL maintainer="Richard Pappalardo " 6 | 7 | #---------------------------------------------------------------------------------------------------------------------- 8 | #-- Test tools -------------------------------------------------------------------------------------------------------- 9 | #---------------------------------------------------------------------------------------------------------------------- 10 | 11 | RUN apt-get install -y jq \ 12 | && apt-get clean 13 | 14 | USER worker:worker 15 | 16 | ENV GOOGLE_SDK_DOWNLOAD ./gcloud.tar.gz 17 | ENV GOOGLE_SDK_VERSION 478 18 | 19 | ENV TEST_TOOLS /builds/worker/test-tools 20 | ENV PATH ${PATH}:${TEST_TOOLS}:${TEST_TOOLS}/google-cloud-sdk/bin 21 | 22 | RUN mkdir -p ${TEST_TOOLS} && \ 23 | mkdir -p ${HOME}/.config/gcloud 24 | 25 | RUN curl https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-${GOOGLE_SDK_VERSION}.0.0-linux-x86_64.tar.gz --output ${GOOGLE_SDK_DOWNLOAD} \ 26 | && tar -xvf ${GOOGLE_SDK_DOWNLOAD} -C ${TEST_TOOLS} \ 27 | && rm -f ${GOOGLE_SDK_DOWNLOAD} \ 28 | && ${TEST_TOOLS}/google-cloud-sdk/install.sh --quiet \ 29 | && ${TEST_TOOLS}/google-cloud-sdk/bin/gcloud --quiet components update 30 | 31 | ENV FLANK_DOWNLOAD ${TEST_TOOLS}/flank.jar 32 | ENV FLANK_VERSION 23.10.1 33 | RUN curl -L https://github.com/Flank/flank/releases/download/v${FLANK_VERSION}/flank.jar --output ${FLANK_DOWNLOAD} \ 34 | && chmod +x ${FLANK_DOWNLOAD} 35 | 36 | # run-task expects to run as root 37 | USER root 38 | -------------------------------------------------------------------------------- /taskcluster/kinds/build-bundle/kind.yml: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | --- 5 | loader: taskgraph.loader.transform:loader 6 | 7 | transforms: 8 | - rb_taskgraph.transforms.variant:transforms 9 | - rb_taskgraph.transforms.build_aab:transforms 10 | - taskgraph.transforms.run:transforms 11 | - taskgraph.transforms.task:transforms 12 | 13 | kind-dependencies: 14 | - toolchain 15 | 16 | 17 | task-defaults: 18 | aab-artifact-template: 19 | type: file 20 | name: public/target.aab 21 | path: '/builds/worker/checkouts/vcs/app/build/outputs/bundle/{variant}/app-{variant}.aab' 22 | description: Build AAB (Android App Bundle) from source code. 23 | fetches: 24 | toolchain: 25 | - android-sdk-linux 26 | - android-gradle-dependencies 27 | run: 28 | using: gradlew 29 | use-caches: false 30 | treeherder: 31 | kind: build 32 | symbol: AAB 33 | tier: 2 34 | worker-type: b-android 35 | worker: 36 | docker-image: {in-tree: base} 37 | max-run-time: 7200 38 | chain-of-trust: true 39 | 40 | 41 | tasks: 42 | nightly: 43 | attributes: 44 | nightly: true 45 | run-on-tasks-for: [] 46 | include-nightly-version: true 47 | include-shippable-secrets: true 48 | run: 49 | gradlew: ["-PcrashReportEnabled=true", "-Ptelemetry=true", "-Paab", "bundleNightly"] 50 | -------------------------------------------------------------------------------- /taskcluster/kinds/build/kind.yml: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | --- 5 | loader: taskgraph.loader.transform:loader 6 | 7 | transforms: 8 | - rb_taskgraph.transforms.variant:transforms 9 | - rb_taskgraph.transforms.build_apk:transforms 10 | - taskgraph.transforms.run:transforms 11 | - taskgraph.transforms.task:transforms 12 | 13 | kind-dependencies: 14 | - toolchain 15 | 16 | 17 | task-defaults: 18 | # Builds generate multiple APKs with different ABIs. For each APK described 19 | # by `gradlew printVariants`, an artifact will be generated. `variant` and 20 | # the per-apk config from `printVariants` can be used as subsistutions in 21 | # `name` and `path`. 22 | apk-artifact-template: 23 | type: file 24 | name: public/target.{abi}.apk 25 | path: '/builds/worker/checkouts/vcs/app/build/outputs/apk/{gradle_build_type}/{fileName}' 26 | description: Build Reference Browser from source code. 27 | fetches: 28 | toolchain: 29 | - android-sdk-linux 30 | - android-gradle-dependencies 31 | treeherder: 32 | kind: build 33 | symbol: B 34 | tier: 2 35 | run: 36 | using: gradlew 37 | use-caches: false 38 | worker-type: b-android 39 | worker: 40 | docker-image: {in-tree: base} 41 | max-run-time: 7200 42 | chain-of-trust: true 43 | 44 | tasks: 45 | nightly: 46 | attributes: 47 | nightly: true 48 | run-on-tasks-for: [] 49 | include-nightly-version: true 50 | include-shippable-secrets: true 51 | run: 52 | gradlew: ["-PcrashReportEnabled=true", "-Ptelemetry=true", "assembleNightly"] 53 | raptor: 54 | run-on-tasks-for: [github-push] 55 | run: 56 | gradlew: ["assembleRaptor"] 57 | debug: 58 | attributes: 59 | code-review: true 60 | run-on-tasks-for: 61 | - github-push 62 | - github-pull-request 63 | - github-pull-request-untrusted 64 | run: 65 | gradlew: ["assembleDebug"] 66 | -------------------------------------------------------------------------------- /taskcluster/kinds/bump/kind.yml: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | --- 5 | loader: taskgraph.loader.transform:loader 6 | 7 | kind-dependencies: [] 8 | 9 | transforms: 10 | - rb_taskgraph.transforms.secrets:transforms 11 | - taskgraph.transforms.run:transforms 12 | - taskgraph.transforms.task:transforms 13 | 14 | task-defaults: 15 | description: Build Reference Browser from source code. 16 | treeherder: 17 | kind: build 18 | symbol: bump(a-c) 19 | tier: 2 20 | platform: android-all/opt 21 | run-on-tasks-for: [] 22 | run: 23 | dummy-secrets: 24 | by-level: 25 | '3': [] 26 | default: 27 | - content: "faketoken" 28 | path: .github_token 29 | secrets: 30 | by-level: 31 | '3': 32 | - name: project/mobile/github 33 | key: botAccountToken 34 | path: .github_token 35 | default: [] 36 | using: run-commands 37 | use-caches: false 38 | worker-type: b-android 39 | worker: 40 | docker-image: {in-tree: bump} 41 | max-run-time: 7200 42 | chain-of-trust: true 43 | 44 | tasks: 45 | android-components: 46 | attributes: 47 | bump-type: android-components 48 | description: Bump android-components to the latest version 49 | run: 50 | commands: 51 | - [automation/taskcluster/update_android_components.sh] 52 | -------------------------------------------------------------------------------- /taskcluster/kinds/docker-image/kind.yml: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | --- 5 | 6 | loader: taskgraph.loader.transform:loader 7 | 8 | transforms: 9 | - taskgraph.transforms.docker_image:transforms 10 | - taskgraph.transforms.cached_tasks:transforms 11 | - taskgraph.transforms.task:transforms 12 | 13 | tasks: 14 | android-build: 15 | symbol: I(agb) 16 | parent: base 17 | base: 18 | symbol: I(base) 19 | bump: 20 | parent: base 21 | symbol: I(bump) 22 | ui-tests: 23 | parent: base 24 | symbol: I(ui-tests) 25 | -------------------------------------------------------------------------------- /taskcluster/kinds/fetch/kind.yml: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | --- 5 | loader: taskgraph.loader.transform:loader 6 | 7 | transforms: 8 | - taskgraph.transforms.fetch:transforms 9 | - taskgraph.transforms.run:transforms 10 | - taskgraph.transforms.task:transforms 11 | 12 | task-defaults: 13 | docker-image: {in-tree: base} 14 | 15 | tasks: 16 | android-sdk: 17 | description: Android SDK 18 | fetch: 19 | type: static-url 20 | url: https://dl.google.com/android/repository/commandlinetools-linux-13114758_latest.zip 21 | artifact-name: sdk-tools-linux.zip 22 | sha256: 7ec965280a073311c339e571cd5de778b9975026cfcbe79f2b1cdcb1e15317ee 23 | size: 164760899 24 | artifact-prefix: mobile/android-sdk 25 | fetch-alias: android-sdk 26 | -------------------------------------------------------------------------------- /taskcluster/kinds/geckoview/kind.yml: -------------------------------------------------------------------------------- 1 | --- 2 | loader: taskgraph.loader.transform:loader 3 | transforms: 4 | - taskgraph.transforms.run:transforms 5 | - taskgraph.transforms.task:transforms 6 | 7 | tasks: 8 | nightly: 9 | description: "upstream nightly job" 10 | run: 11 | using: index-search 12 | index-search: 13 | - gecko.v2.mozilla-central.shippable.latest.mobile.android-x86_64-opt 14 | worker-type: always-optimized 15 | -------------------------------------------------------------------------------- /taskcluster/kinds/lint/kind.yml: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | --- 5 | 6 | loader: taskgraph.loader.transform:loader 7 | 8 | transforms: 9 | - taskgraph.transforms.run:transforms 10 | - taskgraph.transforms.task:transforms 11 | 12 | kind-dependencies: 13 | - toolchain 14 | 15 | 16 | task-defaults: 17 | attributes: 18 | code-review: true 19 | fetches: 20 | toolchain: 21 | - android-sdk-linux 22 | - android-gradle-dependencies 23 | run: 24 | use-caches: false 25 | treeherder: 26 | kind: test 27 | platform: 'lint/opt' 28 | tier: 1 29 | worker-type: b-android 30 | worker: 31 | docker-image: {in-tree: base} 32 | max-run-time: 7200 33 | 34 | 35 | tasks: 36 | compare-locales: 37 | description: 'Validate strings.xml with compare-locales' 38 | run: 39 | using: run-task 40 | cwd: '{checkout}' 41 | command: 'pip install --user "compare-locales>=4.0.1,<5.0" && compare-locales --validate l10n.toml .' 42 | treeherder: 43 | symbol: compare-locale 44 | tier: 2 45 | dependency-analysis: 46 | description: 'Running dependency-analysis over all modules' 47 | run: 48 | using: gradlew 49 | gradlew: [buildHealth] 50 | treeherder: 51 | symbol: deps 52 | worker: 53 | artifacts: 54 | - name: public/build-health-report.txt 55 | path: /builds/worker/checkouts/vcs/build/reports/dependency-analysis/build-health-report.txt 56 | type: file 57 | detekt: 58 | description: 'Running detekt over all modules' 59 | run: 60 | using: gradlew 61 | gradlew: [detekt] 62 | treeherder: 63 | symbol: detekt 64 | ktlint: 65 | description: 'Running ktlint over all modules' 66 | run: 67 | using: gradlew 68 | gradlew: [ktlint] 69 | treeherder: 70 | symbol: ktlint 71 | lint: 72 | description: 'Running lint over all modules' 73 | run: 74 | using: gradlew 75 | gradlew: [lintDebug] 76 | treeherder: 77 | symbol: lint 78 | -------------------------------------------------------------------------------- /taskcluster/kinds/pr/kind.yml: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | --- 5 | loader: taskgraph.loader.transform:loader 6 | 7 | kind-dependencies: 8 | - lint 9 | - build 10 | - test 11 | 12 | transforms: 13 | - taskgraph.transforms.code_review:transforms 14 | - taskgraph.transforms.task:transforms 15 | 16 | tasks: 17 | complete: 18 | description: PR Summary Task 19 | run-on-tasks-for: 20 | - github-pull-request 21 | - github-pull-request-untrusted 22 | worker-type: succeed 23 | -------------------------------------------------------------------------------- /taskcluster/kinds/push-bundle/kind.yml: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | --- 5 | 6 | loader: rb_taskgraph.loader.single_dep:loader 7 | 8 | kind-dependencies: 9 | - signing-bundle 10 | 11 | only-for-attributes: 12 | - nightly 13 | 14 | transforms: 15 | - rb_taskgraph.transforms.push_android_app:transforms 16 | - taskgraph.transforms.task:transforms 17 | 18 | job-template: 19 | description: Publish Reference Browser 20 | treeherder: 21 | kind: build 22 | symbol: gp-aab 23 | worker-type: push-apk 24 | worker: 25 | channel: nightly 26 | commit: true 27 | product: reference-browser 28 | -------------------------------------------------------------------------------- /taskcluster/kinds/signing-bundle/kind.yml: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | --- 5 | 6 | loader: rb_taskgraph.loader.single_dep:loader 7 | 8 | kind-dependencies: 9 | - build-bundle 10 | 11 | transforms: 12 | - rb_taskgraph.transforms.signing:transforms 13 | - rb_taskgraph.transforms.signing_bundle:transforms 14 | - taskgraph.transforms.task:transforms 15 | 16 | job-template: 17 | description: Sign Reference Browser AAB 18 | treeherder: 19 | kind: build 20 | symbol: S-AAB 21 | tier: 2 22 | worker-type: 23 | by-variant: 24 | nightly: signing 25 | default: dep-signing 26 | worker: 27 | max-run-time: 3600 28 | signing-type: 29 | by-variant: 30 | nightly: 31 | by-level: 32 | '3': release-signing 33 | default: dep-signing 34 | default: dep-signing 35 | -------------------------------------------------------------------------------- /taskcluster/kinds/signing/kind.yml: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | --- 5 | 6 | loader: rb_taskgraph.loader.single_dep:loader 7 | 8 | kind-dependencies: 9 | - build 10 | 11 | transforms: 12 | - rb_taskgraph.transforms.signing:transforms 13 | - rb_taskgraph.transforms.signing_apks:transforms 14 | - taskgraph.transforms.task:transforms 15 | 16 | job-template: 17 | description: Sign Reference Browser 18 | index: 19 | by-build-type: 20 | (nightly|raptor): 21 | type: signing 22 | default: {} 23 | treeherder: 24 | kind: build 25 | symbol: S 26 | tier: 2 27 | worker-type: 28 | by-variant: 29 | nightly: signing 30 | default: dep-signing 31 | worker: 32 | max-run-time: 3600 33 | signing-type: 34 | by-variant: 35 | nightly: 36 | by-level: 37 | '3': release-signing 38 | default: dep-signing 39 | default: dep-signing 40 | -------------------------------------------------------------------------------- /taskcluster/kinds/toolchain/android.yml: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | --- 5 | task-defaults: 6 | worker-type: b-android 7 | worker: 8 | max-run-time: 1800 9 | 10 | 11 | linux64-android-sdk-linux-repack: 12 | attributes: 13 | artifact_prefix: mobile/android-sdk 14 | description: "Android SDK (Linux) repack toolchain build" 15 | fetches: 16 | fetch: 17 | - android-sdk 18 | run: 19 | script: repack-android-sdk-linux.sh 20 | resources: [] 21 | toolchain-artifact: mobile/android-sdk/android-sdk-linux.tar.xz 22 | toolchain-alias: android-sdk-linux 23 | treeherder: 24 | symbol: TL(android-sdk-linux) 25 | worker: 26 | docker-image: {in-tree: base} 27 | 28 | 29 | linux64-android-gradle-dependencies: 30 | description: "Android Gradle dependencies toolchain task" 31 | fetches: 32 | toolchain: 33 | # Aliases aren't allowed for toolchains depending on toolchains. 34 | - linux64-android-sdk-linux-repack 35 | run: 36 | script: android-gradle-dependencies.sh 37 | sparse-profile: null 38 | resources: 39 | - taskcluster/scripts/toolchain/android-gradle-dependencies.sh 40 | - taskcluster/scripts/toolchain/android-gradle-dependencies/** 41 | - gradle/libs.versions.toml 42 | toolchain-artifact: public/build/android-gradle-dependencies.tar.xz 43 | toolchain-alias: android-gradle-dependencies 44 | treeherder: 45 | symbol: TL(gradle-dependencies) 46 | worker: 47 | docker-image: {in-tree: android-build} 48 | env: 49 | # TODO do no hardcode 50 | ANDROID_SDK_ROOT: /builds/worker/fetches/android-sdk-linux 51 | -------------------------------------------------------------------------------- /taskcluster/kinds/toolchain/kind.yml: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | --- 5 | loader: taskgraph.loader.transform:loader 6 | 7 | kind-dependencies: 8 | - fetch 9 | 10 | transforms: 11 | - taskgraph.transforms.run:transforms 12 | - taskgraph.transforms.cached_tasks:transforms 13 | - taskgraph.transforms.task:transforms 14 | 15 | 16 | task-defaults: 17 | treeherder: 18 | kind: build 19 | platform: toolchains/opt 20 | tier: 1 21 | run-on-projects: [] 22 | run: 23 | using: toolchain-script 24 | 25 | 26 | tasks-from: 27 | - android.yml 28 | - minidump-stackwalk.yml 29 | -------------------------------------------------------------------------------- /taskcluster/kinds/toolchain/minidump-stackwalk.yml: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | --- 5 | task-defaults: 6 | description: "minidump-stackwalk toolchain" 7 | run: 8 | using: index-search 9 | worker-type: always-optimized 10 | 11 | 12 | linux64-minidump-stackwalk: 13 | run: 14 | index-search: 15 | - gecko.cache.level-3.toolchains.v3.linux64-minidump-stackwalk.latest 16 | treeherder: 17 | symbol: TL(stackwalk) 18 | -------------------------------------------------------------------------------- /taskcluster/rb_taskgraph/__init__.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | 6 | from importlib import import_module 7 | 8 | 9 | def register(graph_config): 10 | """ 11 | Import all modules that are siblings of this one, triggering decorators in 12 | the process. 13 | """ 14 | _import_modules(["job", "worker_types", "routes", "target_tasks"]) 15 | 16 | 17 | def _import_modules(modules): 18 | for module in modules: 19 | import_module(f".{module}", package=__name__) 20 | -------------------------------------------------------------------------------- /taskcluster/rb_taskgraph/loader/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/taskcluster/rb_taskgraph/loader/__init__.py -------------------------------------------------------------------------------- /taskcluster/rb_taskgraph/loader/single_dep.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | 6 | import copy 7 | 8 | from voluptuous import Required 9 | 10 | from taskgraph.task import Task 11 | from taskgraph.util.schema import Schema 12 | 13 | schema = Schema({Required("primary-dependency", "primary dependency task"): Task}) 14 | 15 | 16 | def loader(kind, path, config, params, loaded_tasks): 17 | """ 18 | Load tasks based on the jobs dependant kinds. 19 | 20 | Optional `only-for-attributes` kind configuration, if specified, will limit 21 | the jobs chosen to ones which have the specified attribute, with the specified 22 | value. 23 | 24 | Optional `job-template` kind configuration value, if specified, will be used to 25 | pass configuration down to the specified transforms used. 26 | """ 27 | only_attributes = config.get("only-for-attributes") 28 | job_template = config.get("job-template") 29 | 30 | for task in loaded_tasks: 31 | if task.kind not in config.get("kind-dependencies", []): 32 | continue 33 | 34 | if only_attributes: 35 | config_attrs = set(only_attributes) 36 | if not config_attrs & set(task.attributes): 37 | # make sure any attribute exists 38 | continue 39 | 40 | job = {"primary-dependency": task} 41 | 42 | if job_template: 43 | job.update(copy.deepcopy(job_template)) 44 | 45 | yield job 46 | -------------------------------------------------------------------------------- /taskcluster/rb_taskgraph/routes.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | 6 | import time 7 | 8 | from taskgraph.transforms.task import index_builder 9 | 10 | SIGNING_ROUTE_TEMPLATES = [ 11 | "index.{trust-domain}.v2.{project}.{variant}.latest.{abi}", 12 | "index.{trust-domain}.v2.{project}.{variant}.{build_date}.revision.{head_rev}.{abi}", 13 | "index.{trust-domain}.v2.{project}.{variant}.{build_date}.latest.{abi}", 14 | "index.{trust-domain}.v2.{project}.{variant}.revision.{head_rev}.{abi}", 15 | ] 16 | 17 | 18 | @index_builder("signing") 19 | def add_signing_indexes(config, task): 20 | if config.params["level"] != "3": 21 | return task 22 | 23 | subs = config.params.copy() 24 | subs["build_date"] = time.strftime( 25 | "%Y.%m.%d", time.gmtime(config.params["build_date"]) 26 | ) 27 | subs["trust-domain"] = config.graph_config["trust-domain"] 28 | subs["variant"] = task["attributes"]["build-type"] 29 | 30 | routes = task.setdefault("routes", []) 31 | for tpl in SIGNING_ROUTE_TEMPLATES: 32 | for abi in task["attributes"]["apks"].keys(): 33 | subs["abi"] = abi 34 | routes.append(tpl.format(**subs)) 35 | 36 | task["routes"] = _deduplicate_and_sort_sequence(routes) 37 | return task 38 | 39 | 40 | def _deduplicate_and_sort_sequence(sequence): 41 | return sorted(list(set(sequence))) 42 | -------------------------------------------------------------------------------- /taskcluster/rb_taskgraph/target_tasks.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | import os 6 | 7 | from redo import retry 8 | from taskgraph.target_tasks import register_target_task 9 | from taskgraph.util.taskcluster import find_task_id 10 | 11 | 12 | def index_exists(index_path, reason=""): 13 | print(f"Looking for existing index {index_path} {reason}...") 14 | try: 15 | task_id = find_task_id(index_path) 16 | print(f"Index {index_path} exists: taskId {task_id}") 17 | return True 18 | except KeyError: 19 | print(f"Index {index_path} doesn't exist.") 20 | return False 21 | 22 | 23 | @register_target_task("nightly") 24 | def target_tasks_nightly(full_task_graph, parameters, graph_config): 25 | """Select the set of tasks required for a nightly build.""" 26 | 27 | def filter(task, parameters): 28 | return task.attributes.get("nightly", False) 29 | 30 | index_path = ( 31 | f"{graph_config['trust-domain']}.v2.{parameters['project']}.branch." 32 | f"{parameters['head_ref']}.revision.{parameters['head_rev']}.taskgraph.decision-nightly" 33 | ) 34 | if os.environ.get("MOZ_AUTOMATION") and retry( 35 | index_exists, 36 | args=(index_path,), 37 | kwargs={ 38 | "reason": "to avoid triggering multiple nightlies off the same revision", 39 | }, 40 | ): 41 | return [] 42 | 43 | return [l for l, t in full_task_graph.tasks.items() if filter(t, parameters)] 44 | 45 | 46 | @register_target_task("bump_android_components") 47 | def target_tasks_bump_android_components(full_task_graph, parameters, graph_config): 48 | """Select the set of tasks required to update android components.""" 49 | 50 | def filter(task, parameters): 51 | return task.attributes.get("bump-type", "") == "android-components" 52 | 53 | return [l for l, t in full_task_graph.tasks.items() if filter(t, parameters)] 54 | -------------------------------------------------------------------------------- /taskcluster/rb_taskgraph/transforms/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozilla-mobile/reference-browser/7cfeb904cd8333c6eb54f2cc39ba5db2c0891755/taskcluster/rb_taskgraph/transforms/__init__.py -------------------------------------------------------------------------------- /taskcluster/rb_taskgraph/transforms/build_aab.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | """ 5 | Apply some defaults and minor modifications to the jobs defined in the build 6 | kind. 7 | """ 8 | 9 | 10 | from taskgraph.transforms.base import TransformSequence 11 | 12 | 13 | transforms = TransformSequence() 14 | 15 | 16 | @transforms.add 17 | def add_artifacts(config, tasks): 18 | for task in tasks: 19 | variant = task["attributes"]["build-type"] 20 | artifacts = task.setdefault("worker", {}).setdefault("artifacts", []) 21 | if "aab-artifact-template" in task: 22 | artifact_template = task.pop("aab-artifact-template") 23 | artifacts.append({ 24 | "type": artifact_template["type"], 25 | "name": artifact_template["name"], 26 | "path": artifact_template["path"].format(variant=variant), 27 | }) 28 | task["attributes"]["aab"] = artifact_template["name"] 29 | 30 | yield task 31 | -------------------------------------------------------------------------------- /taskcluster/rb_taskgraph/transforms/build_apk.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | """ 5 | Apply some defaults and minor modifications to the jobs defined in the build 6 | kind. 7 | """ 8 | 9 | 10 | from taskgraph.transforms.base import TransformSequence 11 | 12 | from ..gradle import get_build_variant 13 | 14 | 15 | transforms = TransformSequence() 16 | 17 | 18 | @transforms.add 19 | def add_artifacts(config, tasks): 20 | for task in tasks: 21 | build_type = task["attributes"]["build-type"] 22 | variant_config = get_build_variant(build_type) 23 | artifacts = task.setdefault("worker", {}).setdefault("artifacts", []) 24 | task["attributes"]["apks"] = apks = {} 25 | if "apk-artifact-template" in task: 26 | artifact_template = task.pop("apk-artifact-template") 27 | for apk in variant_config["apks"]: 28 | apk_name = artifact_template["name"].format(**apk) 29 | artifacts.append({ 30 | "type": artifact_template["type"], 31 | "name": apk_name, 32 | "path": artifact_template["path"].format( 33 | gradle_build_type=build_type, **apk 34 | ), 35 | }) 36 | apks[apk["abi"]] = apk_name 37 | 38 | yield task 39 | -------------------------------------------------------------------------------- /taskcluster/rb_taskgraph/transforms/notify.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | """ 5 | Handle notifications like emails. 6 | """ 7 | 8 | 9 | import copy 10 | import json 11 | 12 | from taskgraph.transforms.base import TransformSequence 13 | from taskgraph.util.treeherder import inherit_treeherder_from_dep 14 | from taskgraph.util.schema import resolve_keyed_by 15 | 16 | transforms = TransformSequence() 17 | 18 | 19 | @transforms.add 20 | def add_notify_email(config, tasks): 21 | for task in tasks: 22 | notify = task.pop('notify', {}) 23 | email_config = notify.get('email') 24 | if email_config: 25 | extra = task.setdefault('extra', {}) 26 | notify = extra.setdefault('notify', {}) 27 | notify['email'] = { 28 | 'content': email_config['content'], 29 | 'subject': email_config['subject'], 30 | 'link': email_config.get('link', None), 31 | } 32 | 33 | routes = task.setdefault('routes', []) 34 | routes.extend([ 35 | f'notify.email.{address}.on-{reason}' 36 | for address in email_config['to-addresses'] 37 | for reason in email_config['on-reasons'] 38 | ]) 39 | 40 | yield task 41 | -------------------------------------------------------------------------------- /taskcluster/rb_taskgraph/transforms/push_android_app.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | """ 5 | Apply some defaults and minor modifications to the jobs defined in the 6 | push_bundle kind. 7 | """ 8 | 9 | 10 | from taskgraph.transforms.base import TransformSequence 11 | from taskgraph.util.treeherder import inherit_treeherder_from_dep 12 | 13 | 14 | transforms = TransformSequence() 15 | 16 | 17 | @transforms.add 18 | def build_android_app_task(config, tasks): 19 | for task in tasks: 20 | dep = task.pop("primary-dependency") 21 | task["attributes"] = dep.attributes.copy() 22 | if "aab" in task["attributes"]: 23 | paths = ["public/target.aab"] 24 | task_type = "signing-bundle" 25 | else: 26 | paths = list(dep.attributes["apks"].values()) 27 | task_type = "signing" 28 | task["dependencies"] = {task_type: dep.label} 29 | task["name"] = dep.label[len(dep.kind) + 1 :] 30 | if "run_on_tasks_for" in task["attributes"]: 31 | task["run-on-tasks-for"] = task["attributes"]["run_on_tasks_for"] 32 | 33 | task["treeherder"] = inherit_treeherder_from_dep(task, dep) 34 | task["worker"]["upstream-artifacts"] = [ 35 | { 36 | "taskId": {"task-reference": f"<{task_type}>"}, 37 | "taskType": "signing", 38 | "paths": paths, 39 | } 40 | ] 41 | task["worker"]["dep"] = config.params["level"] != "3" 42 | yield task 43 | -------------------------------------------------------------------------------- /taskcluster/rb_taskgraph/transforms/secrets.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | """ 5 | Resolve secrets and dummy secrets 6 | """ 7 | 8 | 9 | from taskgraph.transforms.base import TransformSequence 10 | from taskgraph.util.schema import resolve_keyed_by 11 | 12 | 13 | transforms = TransformSequence() 14 | 15 | 16 | @transforms.add 17 | def resolve_keys(config, tasks): 18 | for task in tasks: 19 | for key in ("run.secrets", "run.dummy-secrets"): 20 | resolve_keyed_by( 21 | task, 22 | key, 23 | item_name=task["name"], 24 | level=config.params["level"] 25 | ) 26 | yield task 27 | -------------------------------------------------------------------------------- /taskcluster/rb_taskgraph/transforms/signing.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | """ 5 | Apply some defaults and minor modifications to the jobs defined in the build 6 | kind. 7 | """ 8 | 9 | 10 | from taskgraph.transforms.base import TransformSequence 11 | from taskgraph.util.treeherder import inherit_treeherder_from_dep 12 | from taskgraph.util.schema import resolve_keyed_by 13 | 14 | 15 | transforms = TransformSequence() 16 | 17 | 18 | @transforms.add 19 | def define_signing_flags(config, tasks): 20 | for task in tasks: 21 | dep = task["primary-dependency"] 22 | # Current kind will be prepended later in the transform chain. 23 | task["name"] = _get_dependent_job_name_without_its_kind(dep) 24 | task["attributes"] = dep.attributes.copy() 25 | task["attributes"]["signed"] = True 26 | if "run_on_tasks_for" in task["attributes"]: 27 | task["run-on-tasks-for"] = task["attributes"]["run_on_tasks_for"] 28 | 29 | for key in ("index", "worker-type", "worker.signing-type"): 30 | resolve_keyed_by( 31 | task, 32 | key, 33 | item_name=task["name"], 34 | variant=task["attributes"]["build-type"], 35 | **{ 36 | "build-type": task["attributes"]["build-type"], 37 | "level": config.params["level"], 38 | } 39 | ) 40 | task["treeherder"] = inherit_treeherder_from_dep(task, dep) 41 | yield task 42 | 43 | 44 | def _get_dependent_job_name_without_its_kind(dependent_job): 45 | return dependent_job.label[len(dependent_job.kind) + 1:] 46 | -------------------------------------------------------------------------------- /taskcluster/rb_taskgraph/transforms/signing_apks.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | """ 5 | Apply some defaults and minor modifications to the jobs defined in the build 6 | kind. 7 | """ 8 | 9 | 10 | from taskgraph.transforms.base import TransformSequence 11 | 12 | transforms = TransformSequence() 13 | 14 | 15 | @transforms.add 16 | def build_signing_task(config, tasks): 17 | for task in tasks: 18 | dep = task["primary-dependency"] 19 | task["dependencies"] = {"build": dep.label} 20 | task["worker"]["upstream-artifacts"] = [ 21 | { 22 | "taskId": {"task-reference": ""}, 23 | "taskType": "build", 24 | "paths": list(dep.attributes["apks"].values()), 25 | "formats": ["gcp_prod_autograph_apk"], 26 | } 27 | ] 28 | del task["primary-dependency"] 29 | yield task 30 | -------------------------------------------------------------------------------- /taskcluster/rb_taskgraph/transforms/signing_bundle.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | """ 5 | Apply some defaults and minor modifications to the jobs defined in the build 6 | kind. 7 | """ 8 | 9 | 10 | from taskgraph.transforms.base import TransformSequence 11 | 12 | 13 | transforms = TransformSequence() 14 | 15 | 16 | @transforms.add 17 | def build_signing_task(config, tasks): 18 | for task in tasks: 19 | dep = task["primary-dependency"] 20 | task["dependencies"] = {"build-bundle": dep.label} 21 | task["worker"]["upstream-artifacts"] = [{ 22 | "taskId": {"task-reference": ""}, 23 | "taskType": "build", 24 | "paths": [dep.attributes["aab"]], 25 | "formats": ["gcp_prod_autograph_aab"], 26 | }] 27 | del task["primary-dependency"] 28 | yield task 29 | -------------------------------------------------------------------------------- /taskcluster/rb_taskgraph/transforms/variant.py: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | """ 5 | Apply some defaults and minor modifications to the jobs defined in the build 6 | kind. 7 | """ 8 | 9 | 10 | import datetime 11 | 12 | from taskgraph.transforms.base import TransformSequence 13 | 14 | 15 | transforms = TransformSequence() 16 | 17 | 18 | @transforms.add 19 | def add_variant_config(config, tasks): 20 | for task in tasks: 21 | attributes = task.setdefault("attributes", {}) 22 | variant = attributes["build-type"] if attributes.get("build-type") else task["name"] 23 | attributes["build-type"] = variant 24 | task["treeherder"]["platform"] = f"android/{variant}" 25 | yield task 26 | 27 | 28 | @transforms.add 29 | def add_nightly_version(config, tasks): 30 | formatted_date = datetime.datetime.now().strftime("%y%V") 31 | version_name = f"1.0.{formatted_date}" 32 | 33 | for task in tasks: 34 | if task.pop("include-nightly-version", False): 35 | task["run"]["gradlew"].extend([ 36 | f"-PversionName={version_name}", 37 | "-Pofficial" 38 | ]) 39 | yield task 40 | 41 | @transforms.add 42 | def add_shippable_secrets(config, tasks): 43 | for task in tasks: 44 | secrets = task["run"].setdefault("secrets", []) 45 | dummy_secrets = task["run"].setdefault("dummy-secrets", []) 46 | 47 | if task.pop("include-shippable-secrets", False) and config.params["level"] == "3": 48 | build_type = task["attributes"]["build-type"] 49 | secret_index = f'project/mobile/reference-browser/{build_type}' 50 | secrets.extend([{ 51 | "key": key, 52 | "name": secret_index, 53 | "path": target_file, 54 | } for key, target_file in ( 55 | ('sentry_dsn', '.sentry_token'), 56 | ('firebase', 'app/src/main/res/values/firebase.xml'), 57 | )]) 58 | else: 59 | dummy_secrets.extend([{ 60 | "content": fake_value, 61 | "path": target_file, 62 | } for fake_value, target_file in ( 63 | ("https://fake@sentry.prod.mozaws.net/368", ".sentry_token"), 64 | )]) 65 | 66 | yield task 67 | -------------------------------------------------------------------------------- /taskcluster/requirements.in: -------------------------------------------------------------------------------- 1 | # For instructions on managing dependencies, see: 2 | # https://taskcluster-taskgraph.readthedocs.io/en/latest/howto/bootstrap-taskgraph.html 3 | 4 | redo 5 | -------------------------------------------------------------------------------- /taskcluster/requirements.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.10 3 | # by the following command: 4 | # 5 | # pip-compile --generate-hashes 6 | # 7 | redo==2.0.4 \ 8 | --hash=sha256:81066955041c853b0e6491eb65a0877dce45131c4cfa3d42d923fc2aa8f7a043 \ 9 | --hash=sha256:c76e4c23ab2f8840261736a851323cd98493710e7a9d36a1058535dca501f293 10 | # via -r requirements.in 11 | -------------------------------------------------------------------------------- /taskcluster/scripts/toolchain/android-gradle-dependencies.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This Source Code Form is subject to the terms of the Mozilla Public 4 | # License, v. 2.0. If a copy of the MPL was not distributed with this 5 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 | 7 | set -ex 8 | 9 | function get_abs_path { 10 | local file_path="$1" 11 | echo "$( cd "$(dirname "$file_path")" >/dev/null 2>&1 ; pwd -P )" 12 | } 13 | 14 | CURRENT_DIR="$(get_abs_path $0)" 15 | PROJECT_DIR="$(get_abs_path $CURRENT_DIR/../../../..)" 16 | 17 | pushd $PROJECT_DIR 18 | 19 | . taskcluster/scripts/toolchain/android-gradle-dependencies/before.sh 20 | 21 | # We build everything to be sure to fetch all dependencies 22 | ./gradlew --no-daemon -PgoogleRepo='http://localhost:8081/nexus/content/repositories/google/' -PcentralRepo='http://localhost:8081/nexus/content/repositories/central/' assemble assembleAndroidTest bundle test lint ktlint detekt 23 | 24 | . taskcluster/scripts/toolchain/android-gradle-dependencies/after.sh 25 | 26 | popd 27 | -------------------------------------------------------------------------------- /taskcluster/scripts/toolchain/android-gradle-dependencies/after.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This Source Code Form is subject to the terms of the Mozilla Public 4 | # License, v. 2.0. If a copy of the MPL was not distributed with this 5 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 | 7 | # This is copy of 8 | # https://searchfox.org/mozilla-central/rev/2cd2d511c0d94a34fb7fa3b746f54170ee759e35/taskcluster/scripts/misc/android-gradle-dependencies/after.sh. 9 | # gradle-plugins was removed because it's not used in this project. 10 | 11 | set -x -e 12 | 13 | echo "running as" $(id) 14 | 15 | : WORKSPACE ${WORKSPACE:=/builds/worker/workspace} 16 | 17 | set -v 18 | 19 | # Package everything up. 20 | pushd $WORKSPACE 21 | mkdir -p android-gradle-dependencies /builds/worker/artifacts 22 | 23 | cp -R ${NEXUS_WORK}/storage/central android-gradle-dependencies 24 | cp -R ${NEXUS_WORK}/storage/google android-gradle-dependencies 25 | 26 | tar cf - android-gradle-dependencies | xz > /builds/worker/artifacts/android-gradle-dependencies.tar.xz 27 | 28 | popd 29 | -------------------------------------------------------------------------------- /taskcluster/scripts/toolchain/android-gradle-dependencies/before.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This Source Code Form is subject to the terms of the Mozilla Public 4 | # License, v. 2.0. If a copy of the MPL was not distributed with this 5 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 | 7 | # This is a copy of 8 | # https://searchfox.org/mozilla-central/rev/2cd2d511c0d94a34fb7fa3b746f54170ee759e35/taskcluster/scripts/misc/android-gradle-dependencies/before.sh. 9 | # `misc` was renamed into `toolchain` and `/builds/worker/workspace/build` was changed into 10 | # `/builds/worker/checkouts/` 11 | 12 | set -x -e 13 | 14 | echo "running as" $(id) 15 | 16 | : WORKSPACE ${WORKSPACE:=/builds/worker/workspace} 17 | 18 | set -v 19 | 20 | mkdir -p ${NEXUS_WORK}/conf 21 | cp /builds/worker/checkouts/vcs/taskcluster/scripts/toolchain/android-gradle-dependencies/nexus.xml ${NEXUS_WORK}/conf/nexus.xml 22 | 23 | # For the Android build system we want Java 11. However this Nexus installation requires Java 8. 24 | PATH="/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/:$PATH" RUN_AS_USER=worker /opt/sonatype/nexus/bin/nexus restart 25 | 26 | # Wait "a while" for Nexus to actually start. Don't fail if this fails. 27 | wget --quiet --retry-connrefused --waitretry=2 --tries=100 \ 28 | http://localhost:8081/nexus/service/local/status || true 29 | rm -rf status 30 | 31 | # It's helpful when debugging to see the "latest state". 32 | curl http://localhost:8081/nexus/service/local/status || true 33 | 34 | # Verify Nexus has actually started. Fail if this fails. 35 | curl --fail --silent --location http://localhost:8081/nexus/service/local/status | grep 'STARTED' 36 | 37 | # It's helpful when debugging to see the repository configurations. 38 | curl http://localhost:8081/nexus/service/local/repositories || true 39 | -------------------------------------------------------------------------------- /taskcluster/scripts/toolchain/repack-android-sdk-linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export ANDROID_SDK_ROOT=$MOZ_FETCHES_DIR 4 | 5 | JAVA17PATH="/usr/lib/jvm/java-17-openjdk-amd64/bin/:$PATH" 6 | 7 | yes | PATH=$JAVA17PATH "${ANDROID_SDK_ROOT}/cmdline-tools/bin/sdkmanager" --licenses --sdk_root="${ANDROID_SDK_ROOT}" 8 | 9 | # It's nice to have the build logs include the state of the world upon completion. 10 | PATH=$JAVA17PATH "${ANDROID_SDK_ROOT}/cmdline-tools/bin/sdkmanager" --list --sdk_root="${ANDROID_SDK_ROOT}" 11 | 12 | tar cf - -C "$ANDROID_SDK_ROOT" . --transform 's,^\./,android-sdk-linux/,' | xz > "$UPLOAD_DIR/android-sdk-linux.tar.xz" 13 | -------------------------------------------------------------------------------- /taskcluster/scripts/write-dummy-secret.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # This Source Code Form is subject to the terms of the Mozilla Public 4 | # License, v. 2.0. If a copy of the MPL was not distributed with this 5 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 | 7 | 8 | import argparse 9 | import errno 10 | import json 11 | import os 12 | 13 | 14 | def write_secret_to_file(path, secret, key, json_secret=False): 15 | path = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../' + path)) 16 | try: 17 | os.makedirs(os.path.dirname(path)) 18 | except OSError as error: 19 | if error.errno != errno.EEXIST: 20 | raise 21 | print(f"Outputting secret to: {path}") 22 | 23 | with open(path, 'w') as f: 24 | if json_secret: 25 | secret = json.dumps(secret) 26 | f.write(secret) 27 | 28 | 29 | def main(): 30 | parser = argparse.ArgumentParser(description="Store a dummy secret to a file") 31 | 32 | parser.add_argument("-c", dest="content", action="store", help="content of the secret") 33 | parser.add_argument("-f", dest="path", action="store", help="file to save secret to") 34 | parser.add_argument("--json", dest="json", action="store_true", default=False, help="serializes the secret to JSON format") 35 | 36 | result = parser.parse_args() 37 | 38 | write_secret_to_file(result.path, result.content, result.json) 39 | 40 | 41 | if __name__ == "__main__": 42 | main() 43 | --------------------------------------------------------------------------------