diff --git a/.github/PULL_REQUEST_TEMPLATE b/.github/PULL_REQUEST_TEMPLATE
index faaf42e6b..ff9998bb7 100644
--- a/.github/PULL_REQUEST_TEMPLATE
+++ b/.github/PULL_REQUEST_TEMPLATE
@@ -6,18 +6,9 @@
- [ ] **Screenshots**: This PR includes screenshots or GIFs of the changes made or an explanation of why it does not
- [ ] **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. In addition, it includes a screenshot of a successful [accessibility scan](https://play.google.com/store/apps/details?id=com.google.android.apps.accessibility.auditor&hl=en_US) to ensure no new defects are added to the product.
-### QA
-
-- [x] **QA Needed**
-
-### To download an APK when reviewing a PR (after all CI tasks finished running):
-1. Click on `Checks` at the top of the PR page.
-2. Click on the `firefoxci-taskcluster` group on the left to expand all tasks.
-3. Click on the `build-debug` task.
-4. Click on `View task in Taskcluster` in the new `DETAILS` section.
-5. The APK links should be on the right side of the screen, named for each CPU architecture.
-
-### GitHub Automation
-
-
-Used by GitHub Actions.
+### To download an APK when reviewing a PR:
+The PR runs an Android build check (`run-build`) that builds a `forkRelease` variant of the app. If it succeeds, then we upload the apks (signed with debug keys) via Github actions. We also generate a comment with some instructions and a link to help you find the downloads. You can also follow the instructions below:
+1. Click Details next to "run-build (pull_request_target)" after it finishes with a green checkmark.
+2. Click the "Artifacts" drop-down near the top right of the page.
+3. The apk links should be present in the drop-down menu. You can click on the suitable CPU architecture to download a zipped apk file.
+4. Unzip the file and install the apk.
diff --git a/.github/disabled_workflows/comment-on-pr.yml b/.github/disabled_workflows/comment-on-pr.yml
new file mode 100644
index 000000000..9cb1ff193
--- /dev/null
+++ b/.github/disabled_workflows/comment-on-pr.yml
@@ -0,0 +1,24 @@
+name: PR comment
+on:
+ pull_request_target:
+ types: [opened]
+ branches:
+ - fork
+jobs: # Disabled because we cannot build changes from fork PRs using this repo's secrets due to Github limitations. So, the built apk will be from wrong code, so this is pointless.
+ comment-on-pr:
+ runs-on: ubuntu-latest
+ if: "! contains(toJSON(github.event.pull_request.title), '[skip ci]')"
+ steps:
+ - name: Comment on PR with link to checks page
+ uses: mshick/add-pr-comment@v1
+ with:
+ message: |
+ ### Download the built apks
+ You can download the apks built by Github actions **after** the CI checks pass.
+ Please go to the checks page for this PR to find the zipped apk files under the artifacts drop-down, as seen in the example screenshot below.
+
+ Note that you will have to click on the "Android build PR" tab on the left side to see the artifacts.
+
+
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
+ allow-repeats: false
diff --git a/.github/imgs/download-artifacts-screenshot.png b/.github/imgs/download-artifacts-screenshot.png
new file mode 100644
index 000000000..fff039553
Binary files /dev/null and b/.github/imgs/download-artifacts-screenshot.png differ
diff --git a/.github/workflows/android-build-pr.yml b/.github/workflows/android-build-pr.yml
new file mode 100644
index 000000000..28c662c00
--- /dev/null
+++ b/.github/workflows/android-build-pr.yml
@@ -0,0 +1,115 @@
+name: Android build PR
+on:
+ pull_request:
+ branches:
+ - fork
+jobs:
+ run-build:
+ runs-on: ubuntu-latest
+ if: "! contains(toJSON(github.event.pull_request.title), '[skip ci]')"
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+ - name: Setup Java
+ uses: actions/setup-java@v1
+ with:
+ java-version: 11
+ - name: Install Android SDK with pieces Gradle skips
+ run: ./automation/iceraven/install-sdk.sh
+ - name: Create version name
+ run: echo "VERSION_NAME=$(git describe --tags HEAD)" >> $GITHUB_ENV
+ - name: Build forkRelease variant of app
+ uses: eskatos/gradle-command-action@v1
+ with:
+ wrapper-cache-enabled: true
+ dependencies-cache-enabled: true
+ configuration-cache-enabled: true
+ arguments: app:assembleForkRelease -PversionName=${{ env.VERSION_NAME }}
+
+
+ run-testDebug:
+ runs-on: ubuntu-latest
+ if: "! contains(toJSON(github.event.pull_request.title), '[skip ci]')"
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+ - name: Setup Java
+ uses: actions/setup-java@v1
+ with:
+ java-version: 11
+ - name: Run tests
+ uses: eskatos/gradle-command-action@v1
+ with:
+ wrapper-cache-enabled: true
+ dependencies-cache-enabled: true
+ configuration-cache-enabled: true
+ arguments: testDebug
+
+
+ run-detekt:
+ runs-on: ubuntu-latest
+ if: "! contains(toJSON(github.event.pull_request.title), '[skip ci]')"
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+ - name: Setup Java
+ uses: actions/setup-java@v1
+ with:
+ java-version: 11
+ - name: Run detekt
+ uses: eskatos/gradle-command-action@v1
+ with:
+ wrapper-cache-enabled: true
+ dependencies-cache-enabled: true
+ configuration-cache-enabled: true
+ arguments: detekt
+ - name: Archive detekt results
+ uses: actions/upload-artifact@v2
+ with:
+ name: detekt report
+ path: build/reports/detekt.html
+
+
+ run-ktlint:
+ runs-on: ubuntu-latest
+ if: "! contains(toJSON(github.event.pull_request.title), '[skip ci]')"
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+ - name: Setup Java
+ uses: actions/setup-java@v1
+ with:
+ java-version: 11
+ - name: Run ktlint
+ uses: eskatos/gradle-command-action@v1
+ with:
+ wrapper-cache-enabled: true
+ dependencies-cache-enabled: true
+ configuration-cache-enabled: true
+ arguments: ktlint
+
+
+ run-lintDebug:
+ runs-on: ubuntu-latest
+ if: "! contains(toJSON(github.event.pull_request.title), '[skip ci]')"
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+ - name: Setup Java
+ uses: actions/setup-java@v1
+ with:
+ java-version: 11
+ - name: Run lintDebug
+ uses: eskatos/gradle-command-action@v1
+ with:
+ wrapper-cache-enabled: true
+ dependencies-cache-enabled: true
+ configuration-cache-enabled: true
+ arguments: lintDebug
+ - name: Archive lint results
+ uses: actions/upload-artifact@v2
+ with:
+ name: lintDebug report
+ path: app/build/reports/lint-results-debug.html
diff --git a/.github/workflows/android-build.yml b/.github/workflows/android-build.yml
new file mode 100644
index 000000000..9c3f7376c
--- /dev/null
+++ b/.github/workflows/android-build.yml
@@ -0,0 +1,143 @@
+name: Android build
+on:
+ push:
+ branches:
+ - fork
+jobs:
+ run-build:
+ runs-on: ubuntu-latest
+ if: "! contains(toJSON(github.event.commits.*.message), '[skip ci]')"
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+ - name: Setup Java
+ uses: actions/setup-java@v1
+ with:
+ java-version: 11
+ - name: Install Android SDK with pieces Gradle skips
+ run: ./automation/iceraven/install-sdk.sh
+ - name: Create version name
+ run: echo "VERSION_NAME=$(git describe --tags HEAD)" >> $GITHUB_ENV
+ - name: Build forkRelease variant of app
+ uses: eskatos/gradle-command-action@v1
+ with:
+ wrapper-cache-enabled: true
+ dependencies-cache-enabled: true
+ configuration-cache-enabled: true
+ arguments: app:assembleForkRelease -PversionName=${{ env.VERSION_NAME }}
+ - name: Create signed APKs
+ uses: abhijitvalluri/sign-apks@v0.8
+ with:
+ releaseDirectory: app/build/outputs/apk/forkRelease/
+ signingKeyBase64: ${{ secrets.DEBUG_SIGNING_KEY }}
+ alias: ${{ secrets.DEBUG_ALIAS }}
+ keyStorePassword: ${{ secrets.DEBUG_KEY_STORE_PASSWORD }}
+ keyPassword: ${{ secrets.DEBUG_KEY_PASSWORD }}
+ - name: Archive arm64 apk
+ uses: actions/upload-artifact@v2
+ with:
+ name: app-arm64-v8a-forkRelease.apk
+ path: app/build/outputs/apk/forkRelease/app-arm64-v8a-forkRelease.apk
+ - name: Archive armeabi apk
+ uses: actions/upload-artifact@v2
+ with:
+ name: app-armeabi-v7a-forkRelease.apk
+ path: app/build/outputs/apk/forkRelease/app-armeabi-v7a-forkRelease.apk
+ - name: Archive x86 apk
+ uses: actions/upload-artifact@v2
+ with:
+ name: app-x86-forkRelease.apk
+ path: app/build/outputs/apk/forkRelease/app-x86-forkRelease.apk
+ - name: Archive x86_64 apk
+ uses: actions/upload-artifact@v2
+ with:
+ name: app-x86_64-forkRelease.apk
+ path: app/build/outputs/apk/forkRelease/app-x86_64-forkRelease.apk
+
+
+ run-testDebug:
+ runs-on: ubuntu-latest
+ if: "! contains(toJSON(github.event.commits.*.message), '[skip ci]')"
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+ - name: Setup Java
+ uses: actions/setup-java@v1
+ with:
+ java-version: 11
+ - name: Run tests
+ uses: eskatos/gradle-command-action@v1
+ with:
+ wrapper-cache-enabled: true
+ dependencies-cache-enabled: true
+ configuration-cache-enabled: true
+ arguments: testDebug
+
+
+ run-detekt:
+ runs-on: ubuntu-latest
+ if: "! contains(toJSON(github.event.commits.*.message), '[skip ci]')"
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+ - name: Setup Java
+ uses: actions/setup-java@v1
+ with:
+ java-version: 11
+ - name: Run detekt
+ uses: eskatos/gradle-command-action@v1
+ with:
+ wrapper-cache-enabled: true
+ dependencies-cache-enabled: true
+ configuration-cache-enabled: true
+ arguments: detekt
+ - name: Archive detekt results
+ uses: actions/upload-artifact@v2
+ with:
+ name: detekt report
+ path: build/reports/detekt.html
+
+
+ run-ktlint:
+ runs-on: ubuntu-latest
+ if: "! contains(toJSON(github.event.commits.*.message), '[skip ci]')"
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+ - name: Setup Java
+ uses: actions/setup-java@v1
+ with:
+ java-version: 11
+ - name: Run ktlint
+ uses: eskatos/gradle-command-action@v1
+ with:
+ wrapper-cache-enabled: true
+ dependencies-cache-enabled: true
+ configuration-cache-enabled: true
+ arguments: ktlint
+
+
+ run-lintDebug:
+ runs-on: ubuntu-latest
+ if: "! contains(toJSON(github.event.commits.*.message), '[skip ci]')"
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+ - name: Setup Java
+ uses: actions/setup-java@v1
+ with:
+ java-version: 11
+ - name: Run lintDebug
+ uses: eskatos/gradle-command-action@v1
+ with:
+ wrapper-cache-enabled: true
+ dependencies-cache-enabled: true
+ configuration-cache-enabled: true
+ arguments: lintDebug
+ - name: Archive lint results
+ uses: actions/upload-artifact@v2
+ with:
+ name: lintDebug report
+ path: app/build/reports/lint-results-debug.html
diff --git a/.github/workflows/release-automation.yml b/.github/workflows/release-automation.yml
new file mode 100644
index 000000000..699325809
--- /dev/null
+++ b/.github/workflows/release-automation.yml
@@ -0,0 +1,111 @@
+name: Release Automation
+on:
+ create:
+jobs:
+ release-automation:
+ name: Create Release
+ runs-on: ubuntu-latest
+ if: "contains(toJSON(github.event.ref_type), 'tag') && contains(toJSON(github.event.ref), 'iceraven')"
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+ - name: Setup Java
+ uses: actions/setup-java@v1
+ with:
+ java-version: 11
+ - name: Install Android SDK with pieces Gradle skips
+ run: ./automation/iceraven/install-sdk.sh
+ - name: Build forkRelease variant of app
+ uses: eskatos/gradle-command-action@v1
+ with:
+ wrapper-cache-enabled: true
+ dependencies-cache-enabled: true
+ configuration-cache-enabled: true
+ arguments: app:assembleForkRelease -PversionName=${{ github.event.ref }}
+ - name: Create signed APKs
+ uses: abhijitvalluri/sign-apks@v0.8
+ with:
+ releaseDirectory: app/build/outputs/apk/forkRelease/
+ signingKeyBase64: ${{ secrets.DEBUG_SIGNING_KEY }}
+ alias: ${{ secrets.DEBUG_ALIAS }}
+ keyStorePassword: ${{ secrets.DEBUG_KEY_STORE_PASSWORD }}
+ keyPassword: ${{ secrets.DEBUG_KEY_PASSWORD }}
+ - name: Create changelog
+ run: |
+ PREVIOUS_RELEASE_TAG=$(git tag --list iceraven-* --sort=-creatordate | tail -n+2 | head -n 1)
+
+ echo "## Automated release of version ${{ github.event.ref }} browser" >>temp_changelog.md
+ if [[ "$(git log | grep $PREVIOUS_RELEASE_TAG | wc -l)" != "0" ]] ; then
+ # There's a path from the previous release to now
+ echo "" >>temp_changelog.md
+ echo "Click to expand" >>temp_changelog.md
+ echo " " >>temp_changelog.md
+ echo "This is an automated release, consisting of the following changes:" >>temp_changelog.md
+ echo "### Change log (commit history since previous release)" >>temp_changelog.md
+ echo " " >>temp_changelog.md
+ git log ${{ github.event.ref }}...$PREVIOUS_RELEASE_TAG --pretty='format:%C(auto)%h (%as) %s' | head -n 1000 >>temp_changelog.md
+ echo " " >>temp_changelog.md
+ echo " " >>temp_changelog.md
+ echo "" >>temp_changelog.md
+ else
+ echo "This is an automated release, not directly descended from the previous release." >>temp_changelog.md
+ fi
+ echo "**NOTE**: @fork-maintainers, you can edit these auto-generated release notes with a more user-friendly summary of the key changes, if needed." >>temp_changelog.md
+ echo " " >>temp_changelog.md
+
+ - name: Create Release
+ id: create_release
+ uses: actions/create-release@v1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ tag_name: ${{ github.event.ref }}
+ release_name: "Version ${{ github.event.ref }}"
+ draft: false
+ prerelease: false
+ body_path: temp_changelog.md
+
+ - name: Upload arm64 apk
+ uses: actions/upload-release-asset@v1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ upload_url: ${{ steps.create_release.outputs.upload_url }}
+ asset_path: app/build/outputs/apk/forkRelease/app-arm64-v8a-forkRelease.apk
+ asset_name: ${{ github.event.ref }}-browser-arm64-v8a-forkRelease.apk
+ asset_content_type: application/vnd.android.package-archive
+
+
+ - name: Upload armeabi apk
+ uses: actions/upload-release-asset@v1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ upload_url: ${{ steps.create_release.outputs.upload_url }}
+ asset_path: app/build/outputs/apk/forkRelease/app-armeabi-v7a-forkRelease.apk
+ asset_name: ${{ github.event.ref }}-browser-armeabi-v7a-forkRelease.apk
+ asset_content_type: application/vnd.android.package-archive
+
+
+ - name: Upload x86 apk
+ uses: actions/upload-release-asset@v1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ upload_url: ${{ steps.create_release.outputs.upload_url }}
+ asset_path: app/build/outputs/apk/forkRelease/app-x86-forkRelease.apk
+ asset_name: ${{ github.event.ref }}-browser-x86-forkRelease.apk
+ asset_content_type: application/vnd.android.package-archive
+
+
+ - name: Upload x86_64 apk
+ uses: actions/upload-release-asset@v1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ upload_url: ${{ steps.create_release.outputs.upload_url }}
+ asset_path: app/build/outputs/apk/forkRelease/app-x86_64-forkRelease.apk
+ asset_name: ${{ github.event.ref }}-browser-x86_64-forkRelease.apk
+ asset_content_type: application/vnd.android.package-archive
diff --git a/.mergify.yml b/.mergify.yml
index de81dd583..73ed4d7c5 100644
--- a/.mergify.yml
+++ b/.mergify.yml
@@ -1,20 +1,7 @@
queue_rules:
- name: default
conditions:
- - or:
- - status-success=complete-pr
- - and:
- # For more context, see "Auto Merge" rules down below
- - status-success=complete-push
- - or:
- - and:
- - base~=^releases[_/].*
- - or:
- - head~=^automation/sync-strings-\d+
- - head~=^relbot/fenix-\d+
- - and:
- - base=main
- - head~=^relbot/AC-Nightly-.+
+ - status-success=pr-complete
pull_request_rules:
- name: Resolve conflict
conditions:
@@ -22,64 +9,94 @@ pull_request_rules:
actions:
comment:
message: This pull request has conflicts when rebasing. Could you fix it @{{author}}? 🙏
- - name: Android-Components bump - Auto Merge
+ - name: MickeyMoz - Auto Merge
conditions:
- - and:
- - files=buildSrc/src/main/java/AndroidComponents.kt
- - -files~=^(?!buildSrc/src/main/java/AndroidComponents.kt).+$
- - author=github-actions[bot]
- - status-success=complete-push
- - or:
- - and:
- - base=main
- - head~=^relbot/AC-Nightly-.+
- - and:
- - base~=^releases[_/].*
- - head~=^relbot/fenix-\d+
+ - author=MickeyMoz
+ - status-success=pr-complete
+ - files~=(Gecko.kt|AndroidComponents.kt)
actions:
review:
type: APPROVE
- message: 🚢
+ message: MickeyMoz 💪
queue:
method: rebase
name: default
rebase_fallback: none
- name: L10N - Auto Merge
conditions:
- - and:
- - files~=^(l10n.toml|app/src/main/res/values[A-Za-z-]*/strings\.xml)$
- # /!\ The line above doesn't prevent random files to be changed alongside
- # l10n ones. That's why the additional condition exists below. For more
- # information: https://docs.mergify.com/conditions/#how-to-match-lists
- - -files~=^(?!(l10n.toml|app/src/main/res/values[A-Za-z-]*/strings\.xml)).+$
- - or:
- - and:
- - author=mozilla-l10n-automation-bot
- - base=main
- - head=import-l10n
- - status-success=complete-pr
- - and:
- - author=github-actions[bot]
- - base~=^releases[_/].*
- - head~=^automation/sync-strings-\d+
- - status-success=complete-push
- # Taskcluster only runs on git-push events because github-actions[bot] is not considered
- # a collaborator, so pull request events are triggered. That said, github-actions[bot]
- # doesn't create the PR on a separate fork (unlike mozilla-l10n-automation-bot). That's
- # why git-push events are taken into account
+ - author=mozilla-l10n-automation-bot
+ - status-success=pr-complete
+ - files~=(strings.xml|l10n.toml)
actions:
review:
type: APPROVE
message: LGTM 😎
queue:
- method: squash
+ method: rebase
+ name: default
+ rebase_fallback: none
+ - name: Release automation (Old)
+ conditions:
+ - base~=releases[_/].*
+ - author=github-actions[bot]
+ # Listing checks manually beause we do not have a "push complete" check yet.
+ - check-success=build-android-test-debug
+ - check-success=build-debug
+ - check-success=build-nightly-simulation
+ - check-success=lint-compare-locales
+ - check-success=lint-detekt
+ - check-success=lint-ktlint
+ - check-success=lint-lint
+ - check-success=signing-android-test-debug
+ - check-success=signing-debug
+ - check-success=signing-nightly-simulation
+ - check-success=test-debug
+ # TODO Temporarily disabled - should be renamed to -build
+ #- check-success=ui-test-x86-debug
+ - files~=(AndroidComponents.kt)
+ actions:
+ review:
+ type: APPROVE
+ message: 🚢
+ queue:
+ method: rebase
+ name: default
+ rebase_fallback: none
+ delete_head_branch:
+ force: false
+ - name: Release automation (New)
+ conditions:
+ - base~=releases[_/].*
+ - author=github-actions[bot]
+ # Listing checks manually beause we do not have a "push complete" check yet.
+ - check-success=build-android-test-beta
+ - check-success=build-android-test-debug
+ - check-success=build-beta-firebase
+ - check-success=build-debug
+ - check-success=build-nightly-simulation
+ - check-success=lint-compare-locales
+ - check-success=lint-detekt
+ - check-success=lint-ktlint
+ - check-success=lint-lint
+ - check-success=signing-android-test-beta
+ - check-success=signing-beta-firebase
+ - check-success=signing-nightly-simulation
+ - check-success=test-debug
+ - check-success=ui-test-x86-beta
+ - files~=(AndroidComponents.kt)
+ actions:
+ review:
+ type: APPROVE
+ message: 🚢
+ queue:
+ method: rebase
name: default
rebase_fallback: none
+ delete_head_branch:
+ force: false
- name: Needs landing - Rebase
conditions:
- - or:
- - check-success=complete-pr
- - check-success=complete-push
+ - check-success=pr-complete
- label=pr:needs-landing
- "#approved-reviews-by>=1"
- -draft
@@ -92,10 +109,8 @@ pull_request_rules:
rebase_fallback: none
- name: Needs landing - Squash
conditions:
- - or:
- - check-success=complete-pr
- - check-success=complete-push
- - label=pr:needs-landing-squashed
+ - check-success=pr-complete
+ - label=pr:needs-landing-squashed
- "#approved-reviews-by>=1"
- -draft
- label!=pr:work-in-progress
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 000000000..66e5d32a5
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,16 @@
+language: android
+dist: trusty
+script:
+ # Prepare SDK
+ - sudo mkdir -p /usr/local/android-sdk/licenses/
+ - sudo touch /usr/local/android-sdk/licenses/android-sdk-license
+ - echo "8933bad161af4178b1185d1a37fbf41ea5269c55" | sudo tee -a /usr/local/android-sdk/licenses/android-sdk-license
+ - echo "d56f5187479451eabf01fb78af6dfcb131a6481e" | sudo tee -a /usr/local/android-sdk/licenses/android-sdk-license
+ - echo "24333f8a63b6825ea9c5514f83c2829b004d1fee" | sudo tee -a /usr/local/android-sdk/licenses/android-sdk-license
+ # The build needs this but Gradle refuses to fetch it.
+ - sdkmanager "ndk;21.0.6113669"
+ # Run tests
+ - ./gradlew -q testDebug 2>&1
+ # Make sure a release build builds
+ - ./gradlew assembleForkRelease -PversionName="$(git describe --tags HEAD)"
+
diff --git a/app/build.gradle b/app/build.gradle
index 8759ccd0f..6baa35576 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -34,7 +34,7 @@ android {
}
defaultConfig {
- applicationId "org.mozilla"
+ applicationId "io.github.forkmaintainers"
minSdkVersion Config.minSdkVersion
targetSdkVersion Config.targetSdkVersion
versionCode 1
@@ -66,7 +66,8 @@ android {
def deepLinkSchemeValue = "fenix-dev"
buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
manifestPlaceholders = [
- "deepLinkScheme": deepLinkSchemeValue
+ "deepLinkScheme": deepLinkSchemeValue,
+ "requestLegacyExternalStorage": true
]
// Build flag for "Mozilla Online" variants. See `Config.isMozillaOnline`.
@@ -105,13 +106,19 @@ android {
applicationIdSuffix ".fenix.debug"
resValue "bool", "IS_DEBUG", "true"
pseudoLocalesEnabled true
+ def deepLinkSchemeValue = "fenix-dev"
+ buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
+ manifestPlaceholders = [
+ "deepLinkScheme": deepLinkSchemeValue,
+ "requestLegacyExternalStorage": false
+ ]
}
nightly releaseTemplate >> {
applicationIdSuffix ".fenix"
buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
def deepLinkSchemeValue = "fenix-nightly"
buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
- manifestPlaceholders = ["deepLinkScheme": deepLinkSchemeValue]
+ manifestPlaceholders = ["deepLinkScheme": deepLinkSchemeValue, "requestLegacyExternalStorage": false]
}
beta releaseTemplate >> {
buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
@@ -127,7 +134,8 @@ android {
// - https://issuetracker.google.com/issues/36924841
// - https://issuetracker.google.com/issues/36905922
"sharedUserId": "org.mozilla.firefox.sharedID",
- "deepLinkScheme": deepLinkSchemeValue
+ "deepLinkScheme": deepLinkSchemeValue,
+ "requestLegacyExternalStorage": true
]
}
release releaseTemplate >> {
@@ -144,9 +152,38 @@ android {
// - https://issuetracker.google.com/issues/36924841
// - https://issuetracker.google.com/issues/36905922
"sharedUserId": "org.mozilla.firefox.sharedID",
+ "deepLinkScheme": deepLinkSchemeValue,
+ "requestLegacyExternalStorage": true
+ ]
+ }
+ forkDebug {
+ shrinkResources false
+ minifyEnabled false
+ applicationIdSuffix ".iceraven.debug"
+ resValue "bool", "IS_DEBUG", "true"
+ pseudoLocalesEnabled true
+ // Need to replicate default debug config features
+ signingConfig signingConfigs.debug
+ debuggable true
+ def deepLinkSchemeValue = "iceraven-debug"
+ buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
+ // Use custom default allowed addon list
+ buildConfigField "String", "AMO_COLLECTION_USER", "\"16201230\""
+ buildConfigField "String", "AMO_COLLECTION_NAME", "\"What-I-want-on-Fenix\""
+ }
+ forkRelease releaseTemplate >> {
+ buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
+ applicationIdSuffix ".iceraven"
+ def deepLinkSchemeValue = "iceraven"
+ buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\""
+ manifestPlaceholders = [
"deepLinkScheme": deepLinkSchemeValue
]
+ // Use custom default allowed addon list
+ buildConfigField "String", "AMO_COLLECTION_USER", "\"16201230\""
+ buildConfigField "String", "AMO_COLLECTION_NAME", "\"What-I-want-on-Fenix\""
}
+
}
buildFeatures {
@@ -245,6 +282,7 @@ android.applicationVariants.all { variant ->
println("Flavor: " + variant.flavorName)
println("Telemetry enabled: " + !isDebug)
+
if (useReleaseVersioning) {
// The Google Play Store does not allow multiple APKs for the same app that all have the
// same version code. Therefore we need to have different version codes for our ARM and x86
@@ -281,7 +319,7 @@ android.applicationVariants.all { variant ->
buildConfigField 'String', 'SENTRY_TOKEN', 'null'
if (!isDebug) {
- buildConfigField 'boolean', 'CRASH_REPORTING', 'true'
+ buildConfigField 'boolean', 'CRASH_REPORTING', 'false'
// Reading sentry token from local file (if it exists). In a release task on taskcluster it will be available.
try {
def token = new File("${rootDir}/.sentry_token").text.trim()
@@ -292,7 +330,7 @@ android.applicationVariants.all { variant ->
}
if (!isDebug) {
- buildConfigField 'boolean', 'TELEMETRY', 'true'
+ buildConfigField 'boolean', 'TELEMETRY', 'false'
} else {
buildConfigField 'boolean', 'TELEMETRY', 'false'
}
@@ -555,10 +593,10 @@ dependencies {
implementation Deps.mozilla_lib_crash
implementation Deps.lib_crash_sentry
- implementation Deps.mozilla_lib_push_firebase
implementation Deps.mozilla_lib_state
implementation Deps.mozilla_lib_dataprotect
debugImplementation Deps.leakcanary
+ forkDebugImplementation Deps.leakcanary
implementation Deps.androidx_compose_ui
implementation Deps.androidx_compose_ui_tooling
@@ -585,13 +623,6 @@ dependencies {
implementation Deps.protobuf_javalite
implementation Deps.google_material
- implementation Deps.adjust
- implementation Deps.installreferrer // Required by Adjust
-
- implementation Deps.google_ads_id // Required for the Google Advertising ID
-
- implementation Deps.google_play_store // Required for in-app reviews
-
androidTestImplementation Deps.uiautomator
androidTestImplementation "tools.fastlane:screengrab:2.0.0"
// This Falcon version is added to maven central now required for Screengrab
@@ -715,6 +746,9 @@ if (project.hasProperty("coverage")) {
debug {
testCoverageEnabled true
}
+ forkDebug {
+ testCoverageEnabled true
+ }
}
}
}
diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/HomeScreenTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/HomeScreenTest.kt
index 0d0416f03..de3587719 100644
--- a/app/src/androidTest/java/org/mozilla/fenix/ui/HomeScreenTest.kt
+++ b/app/src/androidTest/java/org/mozilla/fenix/ui/HomeScreenTest.kt
@@ -98,9 +98,6 @@ class HomeScreenTest {
verifyPrivateSessionMessage()
verifyHomeToolbar()
verifyHomeComponent()
- }.openCommonMythsLink {
- verifyUrl("common-myths-about-private-browsing")
- mDevice.pressBack()
}
homeScreen {
diff --git a/app/src/forkDebug/AndroidManifest.xml b/app/src/forkDebug/AndroidManifest.xml
new file mode 100644
index 000000000..3d25c0db6
--- /dev/null
+++ b/app/src/forkDebug/AndroidManifest.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/forkDebug/ic_launcher-web.png b/app/src/forkDebug/ic_launcher-web.png
new file mode 100644
index 000000000..e81034d36
Binary files /dev/null and b/app/src/forkDebug/ic_launcher-web.png differ
diff --git a/app/src/forkDebug/java/org/mozilla/fenix/DebugFenixApplication.kt b/app/src/forkDebug/java/org/mozilla/fenix/DebugFenixApplication.kt
new file mode 100644
index 000000000..7825870b0
--- /dev/null
+++ b/app/src/forkDebug/java/org/mozilla/fenix/DebugFenixApplication.kt
@@ -0,0 +1,27 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.fenix
+
+import android.os.StrictMode
+import androidx.preference.PreferenceManager
+import leakcanary.AppWatcher
+import leakcanary.LeakCanary
+import org.mozilla.fenix.ext.getPreferenceKey
+
+class DebugFenixApplication : FenixApplication() {
+
+ override fun setupLeakCanary() {
+ val isEnabled = components.strictMode.resetAfter(StrictMode.allowThreadDiskReads()) {
+ PreferenceManager.getDefaultSharedPreferences(this)
+ .getBoolean(getPreferenceKey(R.string.pref_key_leakcanary), true)
+ }
+ updateLeakCanaryState(isEnabled)
+ }
+
+ override fun updateLeakCanaryState(isEnabled: Boolean) {
+ AppWatcher.config = AppWatcher.config.copy(enabled = isEnabled)
+ LeakCanary.config = LeakCanary.config.copy(dumpHeap = isEnabled)
+ }
+}
diff --git a/app/src/forkDebug/res/drawable/ic_launcher_foreground.xml b/app/src/forkDebug/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 000000000..844e479ef
--- /dev/null
+++ b/app/src/forkDebug/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/forkDebug/res/mipmap-hdpi/ic_launcher.png b/app/src/forkDebug/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..873b31cf5
Binary files /dev/null and b/app/src/forkDebug/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/forkDebug/res/mipmap-hdpi/ic_launcher_round.png b/app/src/forkDebug/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 000000000..1536d6f1b
Binary files /dev/null and b/app/src/forkDebug/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/app/src/forkDebug/res/mipmap-mdpi/ic_launcher.png b/app/src/forkDebug/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..9cea9ac22
Binary files /dev/null and b/app/src/forkDebug/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/forkDebug/res/mipmap-mdpi/ic_launcher_round.png b/app/src/forkDebug/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 000000000..f7e6606ce
Binary files /dev/null and b/app/src/forkDebug/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/app/src/forkDebug/res/mipmap-xhdpi/ic_launcher.png b/app/src/forkDebug/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..2850da3e9
Binary files /dev/null and b/app/src/forkDebug/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/forkDebug/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/forkDebug/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 000000000..e75172b17
Binary files /dev/null and b/app/src/forkDebug/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/app/src/forkDebug/res/mipmap-xxhdpi/ic_launcher.png b/app/src/forkDebug/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..0b52a7603
Binary files /dev/null and b/app/src/forkDebug/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/forkDebug/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/forkDebug/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 000000000..766d720d7
Binary files /dev/null and b/app/src/forkDebug/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/app/src/forkDebug/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/forkDebug/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..2f0901633
Binary files /dev/null and b/app/src/forkDebug/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/forkDebug/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/forkDebug/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 000000000..39be5c5da
Binary files /dev/null and b/app/src/forkDebug/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/app/src/forkDebug/res/values/colors.xml b/app/src/forkDebug/res/values/colors.xml
new file mode 100644
index 000000000..608bd8ced
--- /dev/null
+++ b/app/src/forkDebug/res/values/colors.xml
@@ -0,0 +1,7 @@
+
+
+
+ @color/debug_launcher_background
+
diff --git a/app/src/forkDebug/res/xml/shortcuts.xml b/app/src/forkDebug/res/xml/shortcuts.xml
new file mode 100644
index 000000000..1873a5af4
--- /dev/null
+++ b/app/src/forkDebug/res/xml/shortcuts.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/forkRelease/res/drawable-hdpi/fenix_search_widget.png b/app/src/forkRelease/res/drawable-hdpi/fenix_search_widget.png
new file mode 100644
index 000000000..ecad435e4
Binary files /dev/null and b/app/src/forkRelease/res/drawable-hdpi/fenix_search_widget.png differ
diff --git a/app/src/forkRelease/res/drawable-hdpi/ic_logo_wordmark_normal.png b/app/src/forkRelease/res/drawable-hdpi/ic_logo_wordmark_normal.png
new file mode 100644
index 000000000..337ee573b
Binary files /dev/null and b/app/src/forkRelease/res/drawable-hdpi/ic_logo_wordmark_normal.png differ
diff --git a/app/src/forkRelease/res/drawable-hdpi/ic_logo_wordmark_private.png b/app/src/forkRelease/res/drawable-hdpi/ic_logo_wordmark_private.png
new file mode 100644
index 000000000..c7bc68d5b
Binary files /dev/null and b/app/src/forkRelease/res/drawable-hdpi/ic_logo_wordmark_private.png differ
diff --git a/app/src/forkRelease/res/drawable-mdpi/ic_logo_wordmark_normal.png b/app/src/forkRelease/res/drawable-mdpi/ic_logo_wordmark_normal.png
new file mode 100644
index 000000000..767ec48c1
Binary files /dev/null and b/app/src/forkRelease/res/drawable-mdpi/ic_logo_wordmark_normal.png differ
diff --git a/app/src/forkRelease/res/drawable-mdpi/ic_logo_wordmark_private.png b/app/src/forkRelease/res/drawable-mdpi/ic_logo_wordmark_private.png
new file mode 100644
index 000000000..9dc6e6809
Binary files /dev/null and b/app/src/forkRelease/res/drawable-mdpi/ic_logo_wordmark_private.png differ
diff --git a/app/src/forkRelease/res/drawable-xhdpi/ic_logo_wordmark_normal.png b/app/src/forkRelease/res/drawable-xhdpi/ic_logo_wordmark_normal.png
new file mode 100644
index 000000000..91bd546d8
Binary files /dev/null and b/app/src/forkRelease/res/drawable-xhdpi/ic_logo_wordmark_normal.png differ
diff --git a/app/src/forkRelease/res/drawable-xhdpi/ic_logo_wordmark_private.png b/app/src/forkRelease/res/drawable-xhdpi/ic_logo_wordmark_private.png
new file mode 100644
index 000000000..f3b6c2626
Binary files /dev/null and b/app/src/forkRelease/res/drawable-xhdpi/ic_logo_wordmark_private.png differ
diff --git a/app/src/forkRelease/res/drawable-xxhdpi/ic_logo_wordmark_normal.png b/app/src/forkRelease/res/drawable-xxhdpi/ic_logo_wordmark_normal.png
new file mode 100644
index 000000000..d2c2a9392
Binary files /dev/null and b/app/src/forkRelease/res/drawable-xxhdpi/ic_logo_wordmark_normal.png differ
diff --git a/app/src/forkRelease/res/drawable-xxhdpi/ic_logo_wordmark_private.png b/app/src/forkRelease/res/drawable-xxhdpi/ic_logo_wordmark_private.png
new file mode 100644
index 000000000..5153f8c8f
Binary files /dev/null and b/app/src/forkRelease/res/drawable-xxhdpi/ic_logo_wordmark_private.png differ
diff --git a/app/src/forkRelease/res/drawable-xxxhdpi/ic_logo_wordmark_normal.png b/app/src/forkRelease/res/drawable-xxxhdpi/ic_logo_wordmark_normal.png
new file mode 100644
index 000000000..bfd0f68f3
Binary files /dev/null and b/app/src/forkRelease/res/drawable-xxxhdpi/ic_logo_wordmark_normal.png differ
diff --git a/app/src/forkRelease/res/drawable-xxxhdpi/ic_logo_wordmark_private.png b/app/src/forkRelease/res/drawable-xxxhdpi/ic_logo_wordmark_private.png
new file mode 100644
index 000000000..7d970aaae
Binary files /dev/null and b/app/src/forkRelease/res/drawable-xxxhdpi/ic_logo_wordmark_private.png differ
diff --git a/app/src/forkRelease/res/drawable/ic_launcher_foreground.xml b/app/src/forkRelease/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 000000000..83d4b9dd1
--- /dev/null
+++ b/app/src/forkRelease/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
diff --git a/app/src/forkRelease/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/forkRelease/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 000000000..7353dbd1f
--- /dev/null
+++ b/app/src/forkRelease/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/forkRelease/res/values/colors.xml b/app/src/forkRelease/res/values/colors.xml
new file mode 100644
index 000000000..27cf937c1
--- /dev/null
+++ b/app/src/forkRelease/res/values/colors.xml
@@ -0,0 +1,7 @@
+
+
+
+ #F6F6F6
+
diff --git a/app/src/forkRelease/res/values/static_strings.xml b/app/src/forkRelease/res/values/static_strings.xml
new file mode 100644
index 000000000..0587640ee
--- /dev/null
+++ b/app/src/forkRelease/res/values/static_strings.xml
@@ -0,0 +1,8 @@
+
+
+
+
+ Iceraven
+
diff --git a/app/src/forkRelease/res/xml/shortcuts.xml b/app/src/forkRelease/res/xml/shortcuts.xml
new file mode 100644
index 000000000..5f1a6c69e
--- /dev/null
+++ b/app/src/forkRelease/res/xml/shortcuts.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index aab865ec7..1be77d026 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -32,6 +32,7 @@
android:extractNativeLibs="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
+ android:requestLegacyExternalStorage="${requestLegacyExternalStorage}"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/NormalTheme"
diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png
new file mode 100644
index 000000000..5bc1f130f
Binary files /dev/null and b/app/src/main/ic_launcher-playstore.png differ
diff --git a/app/src/main/java/com/adjust/sdk/Adjust.java b/app/src/main/java/com/adjust/sdk/Adjust.java
new file mode 100644
index 000000000..5dc3617fa
--- /dev/null
+++ b/app/src/main/java/com/adjust/sdk/Adjust.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2012-2017 adjust GmbH,
+ * http://www.adjust.com
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+package com.adjust.sdk;
+
+public class Adjust {
+ public static void onCreate(AdjustConfig adjustConfig) {
+ }
+
+ public static void onResume() {
+ }
+
+ public static void onPause() {
+ }
+
+ public static void setEnabled(boolean enabled) {
+ }
+
+ public static void gdprForgetMe(Object ignored) {
+ }
+}
diff --git a/app/src/main/java/com/adjust/sdk/AdjustAttribution.java b/app/src/main/java/com/adjust/sdk/AdjustAttribution.java
new file mode 100644
index 000000000..ab6b3badb
--- /dev/null
+++ b/app/src/main/java/com/adjust/sdk/AdjustAttribution.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012-2017 adjust GmbH,
+ * http://www.adjust.com
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package com.adjust.sdk;
+
+import java.io.Serializable;
+
+public class AdjustAttribution implements Serializable {
+ public String network;
+ public String campaign;
+ public String adgroup;
+ public String creative;
+
+ @Override
+ public boolean equals(Object other) {
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return "";
+ }
+}
diff --git a/app/src/main/java/com/adjust/sdk/AdjustConfig.java b/app/src/main/java/com/adjust/sdk/AdjustConfig.java
new file mode 100644
index 000000000..6753dd7d9
--- /dev/null
+++ b/app/src/main/java/com/adjust/sdk/AdjustConfig.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2012-2017 adjust GmbH,
+ * http://www.adjust.com
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package com.adjust.sdk;
+
+import android.content.Context;
+
+import java.util.List;
+
+public class AdjustConfig {
+ public static final String ENVIRONMENT_SANDBOX = "sandbox";
+ public static final String ENVIRONMENT_PRODUCTION = "production";
+
+ public AdjustConfig(Context context, String appToken, String environment) {
+ }
+
+ public AdjustConfig(Context context, String appToken, String environment, boolean allowSuppressLogLevel) {
+ }
+
+ public void setOnAttributionChangedListener(OnAttributionChangedListener onAttributionChangedListener) {
+ }
+
+ public void setLogLevel(LogLevel logLevel) {
+ }
+}
diff --git a/app/src/main/java/com/adjust/sdk/LogLevel.java b/app/src/main/java/com/adjust/sdk/LogLevel.java
new file mode 100644
index 000000000..27ac3de54
--- /dev/null
+++ b/app/src/main/java/com/adjust/sdk/LogLevel.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2012-2017 adjust GmbH,
+ * http://www.adjust.com
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package com.adjust.sdk;
+
+import android.util.Log;
+
+/**
+ * Created by pfms on 11/03/15.
+ */
+public enum LogLevel {
+ VERBOSE(Log.VERBOSE), DEBUG(Log.DEBUG), INFO(Log.INFO), WARN(Log.WARN), ERROR(Log.ERROR), ASSERT(Log.ASSERT), SUPRESS(8);
+ final int androidLogLevel;
+
+ LogLevel(final int androidLogLevel) {
+ this.androidLogLevel = androidLogLevel;
+ }
+
+ public int getAndroidLogLevel() {
+ return androidLogLevel;
+ }
+}
diff --git a/app/src/main/java/com/adjust/sdk/OnAttributionChangedListener.java b/app/src/main/java/com/adjust/sdk/OnAttributionChangedListener.java
new file mode 100644
index 000000000..7efa1c680
--- /dev/null
+++ b/app/src/main/java/com/adjust/sdk/OnAttributionChangedListener.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2012-2017 adjust GmbH,
+ * http://www.adjust.com
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package com.adjust.sdk;
+
+public interface OnAttributionChangedListener {
+ void onAttributionChanged(AdjustAttribution attribution);
+}
diff --git a/app/src/main/java/com/google/android/gms/ads/identifier/AdvertisingIdClient.java b/app/src/main/java/com/google/android/gms/ads/identifier/AdvertisingIdClient.java
new file mode 100644
index 000000000..3c238f76c
--- /dev/null
+++ b/app/src/main/java/com/google/android/gms/ads/identifier/AdvertisingIdClient.java
@@ -0,0 +1,39 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package com.google.android.gms.ads.identifier;
+
+import android.content.Context;
+
+
+public class AdvertisingIdClient {
+
+ public static final class Info {
+
+ private String mId;
+
+ public Info() {
+ mId = "";
+ }
+
+ public Info(String id, Boolean ignored) {
+ // We need to preserve the passed ID to pass Mozilla's tests.
+ mId = id;
+ }
+
+ public String getId() {
+ return mId;
+ }
+
+ public String toString() {
+ return mId;
+ }
+
+ }
+
+ public static Info getAdvertisingIdInfo(Context context) {
+ return new Info();
+ }
+
+}
diff --git a/app/src/main/java/com/google/android/play/core/review/ReviewManager.kt b/app/src/main/java/com/google/android/play/core/review/ReviewManager.kt
new file mode 100644
index 000000000..789802987
--- /dev/null
+++ b/app/src/main/java/com/google/android/play/core/review/ReviewManager.kt
@@ -0,0 +1,24 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+package com.google.android.play.core.review
+class ReviewManager {
+
+ class FakeReviewFlowTaskResult {
+ val isSuccessful: Boolean = false
+ val result: Any = false
+ }
+ class FakeReviewFlowTask {
+ @Suppress("UNUSED_PARAMETER", "UNUSED_EXPRESSION")
+ fun addOnCompleteListener(ignored: (FakeReviewFlowTaskResult) -> Unit) {
+ 1
+ }
+ }
+ fun requestReviewFlow(): FakeReviewFlowTask {
+ return FakeReviewFlowTask()
+ }
+ @Suppress("UNUSED_PARAMETER", "UNUSED_EXPRESSION")
+ fun launchReviewFlow(ignored1: Any, ignored2: Any) {
+ 1
+ }
+}
diff --git a/app/src/main/java/com/google/android/play/core/review/ReviewManagerFactory.java b/app/src/main/java/com/google/android/play/core/review/ReviewManagerFactory.java
new file mode 100644
index 000000000..3506da2ff
--- /dev/null
+++ b/app/src/main/java/com/google/android/play/core/review/ReviewManagerFactory.java
@@ -0,0 +1,17 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package com.google.android.play.core.review;
+
+import android.content.Context;
+import com.google.android.play.core.review.ReviewManager;
+
+
+public class ReviewManagerFactory {
+
+ public static ReviewManager create(Context context) {
+ return new ReviewManager();
+ }
+
+}
diff --git a/app/src/main/java/com/google/firebase/messaging/FirebaseMessagingService.java b/app/src/main/java/com/google/firebase/messaging/FirebaseMessagingService.java
new file mode 100644
index 000000000..79944c9ca
--- /dev/null
+++ b/app/src/main/java/com/google/firebase/messaging/FirebaseMessagingService.java
@@ -0,0 +1,43 @@
+// Copyright 2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.firebase.messaging;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+
+public class FirebaseMessagingService extends Service {
+
+ private final IBinder mBinder = new Binder();
+
+ public void onMessageReceived(RemoteMessage message) {
+ }
+
+ public void onMessageSent(String msgId) {
+ }
+
+ public void onNewToken(String token) {
+ }
+
+ public void onSendError(String msgId, Exception exception) {
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+
+}
diff --git a/app/src/main/java/com/google/firebase/messaging/RemoteMessage.java b/app/src/main/java/com/google/firebase/messaging/RemoteMessage.java
new file mode 100644
index 000000000..24371f8f8
--- /dev/null
+++ b/app/src/main/java/com/google/firebase/messaging/RemoteMessage.java
@@ -0,0 +1,53 @@
+// Copyright 2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.firebase.messaging;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import java.util.Map;
+
+public class RemoteMessage implements Parcelable {
+
+ protected RemoteMessage(Parcel in)
+ {
+ }
+
+ public static final Creator CREATOR = new Creator()
+ {
+ @Override
+ public RemoteMessage createFromParcel(Parcel in)
+ {
+ return new RemoteMessage(in);
+ }
+
+ @Override
+ public RemoteMessage[] newArray(int size)
+ {
+ return new RemoteMessage[size];
+ }
+ };
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ }
+
+ public Map getData() {
+ return null;
+ }
+
+}
diff --git a/app/src/main/java/com/leanplum/Leanplum.java b/app/src/main/java/com/leanplum/Leanplum.java
new file mode 100644
index 000000000..70a6151fe
--- /dev/null
+++ b/app/src/main/java/com/leanplum/Leanplum.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2016, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import android.content.Context;
+import com.leanplum.callbacks.StartCallback;
+import java.util.Map;
+
+public class Leanplum {
+ public static void setAppIdForDevelopmentMode(String appId, String accessKey) {
+ }
+
+ public static void setAppIdForProductionMode(String appId, String accessKey) {
+ }
+
+ public static void setApplicationContext(Context context) {
+ }
+
+ public static void setDeviceId(String deviceId) {
+ }
+
+ public static void setIsTestModeEnabled(boolean isTestModeEnabled) {
+ }
+
+ public static void setUserAttributes(Map userAttributes) {
+ }
+
+ public static void start(Context context) {
+ }
+
+ public static void start(Context context, StartCallback callback) {
+ }
+
+ public static void start(Context context, Map userAttributes) {
+ }
+
+ public static void start(Context context, String userId) {
+ }
+
+ public static void start(Context context, String userId, StartCallback callback) {
+ }
+
+ public static void start(Context context, String userId, Map userAttributes) {
+ }
+
+ public static synchronized void start(final Context context, String userId, Map attributes, StartCallback response) {
+ }
+
+ static synchronized void start(final Context context, final String userId, final Map attributes, StartCallback response, final Boolean isBackground) {
+ }
+
+ public static void track(final String event, double value, String info, Map params) {
+ }
+
+ public static void track(String event) {
+ }
+
+ public static void track(String event, double value) {
+ }
+
+ public static void track(String event, String info) {
+ }
+
+ public static void track(String event, Map params) {
+ }
+
+ public static void track(String event, double value, Map params) {
+ }
+
+ public static void track(String event, double value, String info) {
+ }
+
+ public static String getDeviceId() { return "stub"; }
+
+ public static String getUserId() { return "stub"; }
+}
diff --git a/app/src/main/java/com/leanplum/LeanplumActivityHelper.java b/app/src/main/java/com/leanplum/LeanplumActivityHelper.java
new file mode 100644
index 000000000..489871cf5
--- /dev/null
+++ b/app/src/main/java/com/leanplum/LeanplumActivityHelper.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import android.app.Application;
+
+public class LeanplumActivityHelper {
+ public static void enableLifecycleCallbacks(final Application app) {
+ }
+}
diff --git a/app/src/main/java/com/leanplum/LeanplumPushFirebaseMessagingService.java b/app/src/main/java/com/leanplum/LeanplumPushFirebaseMessagingService.java
new file mode 100644
index 000000000..57d2f8580
--- /dev/null
+++ b/app/src/main/java/com/leanplum/LeanplumPushFirebaseMessagingService.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2016, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import android.annotation.SuppressLint;
+import android.os.Build;
+import android.os.Bundle;
+
+import com.google.firebase.messaging.FirebaseMessagingService;
+import com.google.firebase.messaging.RemoteMessage;
+
+@SuppressLint("Registered")
+public class LeanplumPushFirebaseMessagingService extends FirebaseMessagingService {
+ @Override
+ public void onCreate() {
+ }
+
+ @Override
+ public void onNewToken(String token) {
+ }
+
+ @Override
+ public void onMessageReceived(RemoteMessage remoteMessage) {
+ }
+}
diff --git a/app/src/main/java/com/leanplum/LeanplumPushNotificationCustomizer.java b/app/src/main/java/com/leanplum/LeanplumPushNotificationCustomizer.java
new file mode 100644
index 000000000..f827eb180
--- /dev/null
+++ b/app/src/main/java/com/leanplum/LeanplumPushNotificationCustomizer.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2015, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+import android.app.Notification;
+import android.os.Bundle;
+import androidx.annotation.Nullable;
+import androidx.core.app.NotificationCompat;
+
+/**
+ * Implement LeanplumPushNotificationCustomizer to customize the appearance of notifications.
+ */
+public interface LeanplumPushNotificationCustomizer {
+ /**
+ * Implement this method to customize push notification. Please call {@link
+ * LeanplumPushService#setCustomizer(LeanplumPushNotificationCustomizer)} to activate this method.
+ * Leave this method empty if you want to support 2 lines of text
+ * in BigPicture style push notification and implement {@link
+ * LeanplumPushNotificationCustomizer#customize(Notification.Builder, Bundle, Notification.Style)}
+ *
+ * @param builder NotificationCompat.Builder for push notification.
+ * @param notificationPayload Bundle notification payload.
+ */
+ void customize(NotificationCompat.Builder builder, Bundle notificationPayload);
+
+ /**
+ * Implement this method to support 2 lines of text in BigPicture style push notification,
+ * otherwise implement {@link
+ * LeanplumPushNotificationCustomizer#customize(NotificationCompat.Builder, Bundle)} and leave
+ * this method empty. Please call {@link
+ * LeanplumPushService#setCustomizer(LeanplumPushNotificationCustomizer, boolean)} with true
+ * value to activate this method.
+ *
+ * @param builder Notification.Builder for push notification.
+ * @param notificationPayload Bundle notification payload.
+ * @param notificationStyle - Notification.BigPictureStyle or null - BigPicture style for current
+ * push notification. Call ((Notification.BigPictureStyle) notificationStyle).bigLargeIcon(largeIcon)
+ * if you want to set large icon on expanded push notification. If notificationStyle wasn't null
+ * it will be set to push notification. Note: If you call notificationStyle = new
+ * Notification.BigPictureStyle() or other Notification.Style - there will be no support 2 lines
+ * of text on BigPicture push and you need to call builder.setStyle(notificationStyle) to set
+ * yours expanded layout for push notification.
+ */
+ void customize(Notification.Builder builder, Bundle notificationPayload,
+ @Nullable Notification.Style notificationStyle);
+}
diff --git a/app/src/main/java/com/leanplum/LeanplumPushService.java b/app/src/main/java/com/leanplum/LeanplumPushService.java
new file mode 100644
index 000000000..436cba348
--- /dev/null
+++ b/app/src/main/java/com/leanplum/LeanplumPushService.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2014, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum;
+
+public class LeanplumPushService {
+ public static void setCustomizer(LeanplumPushNotificationCustomizer customizer) {
+ }
+
+ public static void setCustomizer(LeanplumPushNotificationCustomizer customizer,
+ boolean useNotificationBuilderCustomizer) {
+ }
+}
diff --git a/app/src/main/java/com/leanplum/annotations/Parser.java b/app/src/main/java/com/leanplum/annotations/Parser.java
new file mode 100644
index 000000000..2bb6d2b2a
--- /dev/null
+++ b/app/src/main/java/com/leanplum/annotations/Parser.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.annotations;
+
+public class Parser {
+ public static void parseVariables(Object... instances) {
+ }
+}
diff --git a/app/src/main/java/com/leanplum/callbacks/StartCallback.java b/app/src/main/java/com/leanplum/callbacks/StartCallback.java
new file mode 100644
index 000000000..30d437d30
--- /dev/null
+++ b/app/src/main/java/com/leanplum/callbacks/StartCallback.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2013, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.callbacks;
+
+/**
+ * Callback that gets run when Leanplum is started.
+ *
+ * @author Andrew First
+ */
+public abstract class StartCallback implements Runnable {
+ private boolean success;
+
+ public void setSuccess(boolean success) {
+ this.success = success;
+ }
+
+ public void run() {
+ this.onResponse(success);
+ }
+
+ public abstract void onResponse(boolean success);
+}
diff --git a/app/src/main/java/com/leanplum/internal/LeanplumInternal.java b/app/src/main/java/com/leanplum/internal/LeanplumInternal.java
new file mode 100644
index 000000000..8ca36a6b4
--- /dev/null
+++ b/app/src/main/java/com/leanplum/internal/LeanplumInternal.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016, Leanplum, Inc. All rights reserved.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.leanplum.internal;
+
+public class LeanplumInternal {
+ public static void setCalledStart(boolean calledStart) {
+ }
+
+ public static void setHasStarted(boolean hasStarted) {
+ }
+
+ public static void setStartedInBackground(boolean startedInBackground) {
+ }
+}
diff --git a/app/src/main/java/io/github/forkmaintainers/iceraven/components/PagedAddonCollectionProvider.kt b/app/src/main/java/io/github/forkmaintainers/iceraven/components/PagedAddonCollectionProvider.kt
new file mode 100644
index 000000000..7050282f5
--- /dev/null
+++ b/app/src/main/java/io/github/forkmaintainers/iceraven/components/PagedAddonCollectionProvider.kt
@@ -0,0 +1,403 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+@file:Suppress("TooManyFunctions")
+
+package io.github.forkmaintainers.iceraven.components
+
+import android.content.Context
+import android.util.AtomicFile
+import androidx.annotation.VisibleForTesting
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import mozilla.components.concept.fetch.Client
+import mozilla.components.concept.fetch.Request
+import mozilla.components.concept.fetch.isSuccess
+import mozilla.components.feature.addons.Addon
+import mozilla.components.feature.addons.AddonsProvider
+import mozilla.components.support.base.log.logger.Logger
+import mozilla.components.support.ktx.kotlin.sanitizeURL
+import mozilla.components.support.ktx.util.readAndDeserialize
+import mozilla.components.support.ktx.util.writeString
+import org.json.JSONArray
+import org.json.JSONException
+import org.json.JSONObject
+import org.mozilla.fenix.Config
+import org.mozilla.fenix.ext.settings
+import java.io.File
+import java.io.IOException
+import java.util.Date
+import java.util.concurrent.TimeUnit
+
+internal const val API_VERSION = "api/v4"
+internal const val DEFAULT_SERVER_URL = "https://addons.mozilla.org"
+internal const val COLLECTION_FILE_NAME = "%s_components_addon_collection_%s.json"
+internal const val MINUTE_IN_MS = 60 * 1000
+internal const val DEFAULT_READ_TIMEOUT_IN_SECONDS = 20L
+
+/**
+ * Provide access to the collections AMO API.
+ * https://addons-server.readthedocs.io/en/latest/topics/api/collections.html
+ *
+ * Unlike the android-components version, supports multiple-page responses and
+ * custom collection accounts.
+ *
+ * Needs to extend AddonCollectionProvider because AddonsManagerAdapter won't
+ * take just any AddonsProvider.
+ *
+ * @property serverURL The url of the endpoint to interact with e.g production, staging
+ * or testing. Defaults to [DEFAULT_SERVER_URL].
+ * @property maxCacheAgeInMinutes maximum time (in minutes) the collection cache
+ * should remain valid. Defaults to -1, meaning no cache is being used by default.
+ * @property client A reference of [Client] for interacting with the AMO HTTP api.
+ */
+@Suppress("LongParameterList")
+class PagedAddonCollectionProvider(
+ private val context: Context,
+ private val client: Client,
+ private val serverURL: String = DEFAULT_SERVER_URL,
+ private val maxCacheAgeInMinutes: Long = -1
+) : AddonsProvider {
+
+ private val logger = Logger("PagedAddonCollectionProvider")
+
+ private val diskCacheLock = Any()
+
+ /**
+ * Get the account we should be fetching addons from.
+ */
+ private fun getCollectionAccount(): String {
+ var result = context.settings().customAddonsAccount
+ if (Config.channel.isNightlyOrDebug && context.settings().amoCollectionOverrideConfigured()) {
+ result = context.settings().overrideAmoUser
+ }
+
+ logger.info("Determined collection account: ${result}")
+ return result
+ }
+
+ /**
+ * Get the collection name we should be fetching addons from.
+ */
+ private fun getCollectionName(): String {
+ var result = context.settings().customAddonsCollection
+ if (Config.channel.isNightlyOrDebug && context.settings().amoCollectionOverrideConfigured()) {
+ result = context.settings().overrideAmoCollection
+ }
+
+ logger.info("Determined collection name: ${result}")
+ return result
+ }
+
+ /**
+ * Interacts with the collections endpoint to provide a list of available
+ * add-ons. May return a cached response, if available, not expired (see
+ * [maxCacheAgeInMinutes]) and allowed (see [allowCache]).
+ *
+ * @param allowCache whether or not the result may be provided
+ * from a previously cached response, defaults to true.
+ * @param readTimeoutInSeconds optional timeout in seconds to use when fetching
+ * available add-ons from a remote endpoint. If not specified [DEFAULT_READ_TIMEOUT_IN_SECONDS]
+ * will be used.
+ * @param language optional language that will be ignored.
+ * @throws IOException if the request failed, or could not be executed due to cancellation,
+ * a connectivity problem or a timeout.
+ */
+ @Throws(IOException::class)
+ override suspend fun getAvailableAddons(
+ allowCache: Boolean,
+ readTimeoutInSeconds: Long?,
+ language: String?
+ ): List {
+ val cachedAddons = if (allowCache && !cacheExpired(context)) {
+ readFromDiskCache()
+ } else {
+ null
+ }
+
+ val collectionAccount = getCollectionAccount()
+ val collectionName = getCollectionName()
+
+ if (cachedAddons != null) {
+ logger.info("Providing cached list of addons for ${collectionAccount} collection ${collectionName}")
+ return cachedAddons
+ } else {
+ logger.info("Fetching fresh list of addons for ${collectionAccount} collection ${collectionName}")
+ return getAllPages(
+ listOf(
+ serverURL,
+ API_VERSION,
+ "accounts/account",
+ collectionAccount,
+ "collections",
+ collectionName,
+ "addons"
+ ).joinToString("/"),
+ readTimeoutInSeconds ?: DEFAULT_READ_TIMEOUT_IN_SECONDS
+ ).also {
+ // Cache the JSON object before we parse out the addons
+ if (maxCacheAgeInMinutes > 0) {
+ writeToDiskCache(it.toString())
+ }
+ }.getAddons()
+ }
+ }
+
+ /**
+ * Fetches all pages of add-ons from the given URL (following the "next"
+ * field in the returned JSON) and combines the "results" arrays into that
+ * of the first page. Returns that coalesced object.
+ *
+ * @param url URL of the first page to fetch
+ * @param readTimeoutInSeconds timeout in seconds to use when fetching each page.
+ * @throws IOException if the request failed, or could not be executed due to cancellation,
+ * a connectivity problem or a timeout.
+ */
+ @Throws(IOException::class)
+ suspend fun getAllPages(url: String, readTimeoutInSeconds: Long): JSONObject {
+ // Fetch and compile all the pages into one object we can return
+ var compiledResponse: JSONObject? = null
+ // Each page tells us where to get the next page, if there is one
+ var nextURL: String? = url
+ while (nextURL != null) {
+ client.fetch(
+ Request(
+ url = nextURL,
+ readTimeout = Pair(readTimeoutInSeconds, TimeUnit.SECONDS)
+ )
+ )
+ .use { response ->
+ if (!response.isSuccess) {
+ val errorMessage = "Failed to fetch addon collection. Status code: ${response.status}"
+ logger.error(errorMessage)
+ throw IOException(errorMessage)
+ }
+
+ val currentResponse = try {
+ JSONObject(response.body.string(Charsets.UTF_8))
+ } catch (e: JSONException) {
+ throw IOException(e)
+ }
+ if (compiledResponse == null) {
+ compiledResponse = currentResponse
+ } else {
+ // Write the addons into the first response
+ compiledResponse!!.getJSONArray("results").concat(currentResponse.getJSONArray("results"))
+ }
+ nextURL = if (currentResponse.isNull("next")) null else currentResponse.getString("next")
+ }
+ }
+ return compiledResponse!!
+ }
+
+ /**
+ * Fetches given Addon icon from the url and returns a decoded Bitmap
+ * @throws IOException if the request could not be executed due to cancellation,
+ * a connectivity problem or a timeout.
+ */
+ @Throws(IOException::class)
+ suspend fun getAddonIconBitmap(addon: Addon): Bitmap? {
+ var bitmap: Bitmap? = null
+ if (addon.iconUrl != "") {
+ client.fetch(
+ Request(url = addon.iconUrl.sanitizeURL())
+ ).use { response ->
+ if (response.isSuccess) {
+ response.body.useStream {
+ bitmap = BitmapFactory.decodeStream(it)
+ }
+ }
+ }
+ }
+
+ return bitmap
+ }
+
+ @VisibleForTesting
+ internal fun writeToDiskCache(collectionResponse: String) {
+ logger.info("Storing cache file")
+ synchronized(diskCacheLock) {
+ getCacheFile(context).writeString { collectionResponse }
+ }
+ }
+
+ @VisibleForTesting
+ internal fun readFromDiskCache(): List? {
+ logger.info("Loading cache file")
+ synchronized(diskCacheLock) {
+ return getCacheFile(context).readAndDeserialize {
+ JSONObject(it).getAddons()
+ }
+ }
+ }
+
+ @VisibleForTesting
+ internal fun cacheExpired(context: Context): Boolean {
+ return getCacheLastUpdated(context) < Date().time - maxCacheAgeInMinutes * MINUTE_IN_MS
+ }
+
+ @VisibleForTesting
+ internal fun getCacheLastUpdated(context: Context): Long {
+ val file = getBaseCacheFile(context)
+ return if (file.exists()) file.lastModified() else -1
+ }
+
+ private fun getCacheFile(context: Context): AtomicFile {
+ return AtomicFile(getBaseCacheFile(context))
+ }
+
+ private fun getBaseCacheFile(context: Context): File {
+ val collectionAccount = getCollectionAccount()
+ val collectionName = getCollectionName()
+ return File(context.filesDir, COLLECTION_FILE_NAME.format(collectionAccount, collectionName))
+ }
+
+ fun deleteCacheFile(context: Context): Boolean {
+ logger.info("Clearing cache file")
+ synchronized(diskCacheLock) {
+ val file = getBaseCacheFile(context)
+ return if (file.exists()) file.delete() else false
+ }
+ }
+}
+
+internal fun JSONObject.getAddons(): List {
+ val addonsJson = getJSONArray("results")
+ return (0 until addonsJson.length()).map { index ->
+ addonsJson.getJSONObject(index).toAddons()
+ }
+}
+
+internal fun JSONObject.toAddons(): Addon {
+ return with(getJSONObject("addon")) {
+ val download = getDownload()
+ Addon(
+ id = getSafeString("guid"),
+ authors = getAuthors(),
+ categories = getCategories(),
+ createdAt = getSafeString("created"),
+ updatedAt = getSafeString("last_updated"),
+ downloadId = download?.getDownloadId() ?: "",
+ downloadUrl = download?.getDownloadUrl() ?: "",
+ version = getCurrentVersion(),
+ permissions = getPermissions(),
+ translatableName = getSafeMap("name"),
+ translatableDescription = getSafeMap("description"),
+ translatableSummary = getSafeMap("summary"),
+ iconUrl = getSafeString("icon_url"),
+ siteUrl = getSafeString("url"),
+ rating = getRating(),
+ defaultLocale = getSafeString("default_locale").ifEmpty { Addon.DEFAULT_LOCALE }
+ )
+ }
+}
+
+internal fun JSONObject.getRating(): Addon.Rating? {
+ val jsonRating = optJSONObject("ratings")
+ return if (jsonRating != null) {
+ Addon.Rating(
+ reviews = jsonRating.optInt("count"),
+ average = jsonRating.optDouble("average").toFloat()
+ )
+ } else {
+ null
+ }
+}
+
+internal fun JSONObject.getCategories(): List {
+ val jsonCategories = optJSONObject("categories")
+ return if (jsonCategories == null) {
+ emptyList()
+ } else {
+ val jsonAndroidCategories = jsonCategories.getSafeJSONArray("android")
+ (0 until jsonAndroidCategories.length()).map { index ->
+ jsonAndroidCategories.getString(index)
+ }
+ }
+}
+
+internal fun JSONObject.getPermissions(): List {
+ val fileJson = getJSONObject("current_version")
+ .getSafeJSONArray("files")
+ .getJSONObject(0)
+
+ val permissionsJson = fileJson.getSafeJSONArray("permissions")
+ return (0 until permissionsJson.length()).map { index ->
+ permissionsJson.getString(index)
+ }
+}
+
+internal fun JSONObject.getCurrentVersion(): String {
+ return optJSONObject("current_version")?.getSafeString("version") ?: ""
+}
+
+internal fun JSONObject.getDownload(): JSONObject? {
+ return (
+ getJSONObject("current_version")
+ .optJSONArray("files")
+ ?.getJSONObject(0)
+ )
+}
+
+internal fun JSONObject.getDownloadId(): String {
+ return getSafeString("id")
+}
+
+internal fun JSONObject.getDownloadUrl(): String {
+ return getSafeString("url")
+}
+
+internal fun JSONObject.getAuthors(): List {
+ val authorsJson = getSafeJSONArray("authors")
+ return (0 until authorsJson.length()).map { index ->
+ val authorJson = authorsJson.getJSONObject(index)
+
+ Addon.Author(
+ id = authorJson.getSafeString("id"),
+ name = authorJson.getSafeString("name"),
+ username = authorJson.getSafeString("username"),
+ url = authorJson.getSafeString("url")
+ )
+ }
+}
+
+internal fun JSONObject.getSafeString(key: String): String {
+ return if (isNull(key)) {
+ ""
+ } else {
+ getString(key)
+ }
+}
+
+internal fun JSONObject.getSafeJSONArray(key: String): JSONArray {
+ return if (isNull(key)) {
+ JSONArray("[]")
+ } else {
+ getJSONArray(key)
+ }
+}
+
+internal fun JSONObject.getSafeMap(valueKey: String): Map {
+ return if (isNull(valueKey)) {
+ emptyMap()
+ } else {
+ val map = mutableMapOf()
+ val jsonObject = getJSONObject(valueKey)
+
+ jsonObject.keys()
+ .forEach { key ->
+ map[key] = jsonObject.getSafeString(key)
+ }
+ map
+ }
+}
+
+/**
+ * Concatenates the given JSONArray onto this one.
+ */
+internal fun JSONArray.concat(other: JSONArray) {
+ (0 until other.length()).map { index ->
+ put(length(), other.getJSONObject(index))
+ }
+}
diff --git a/app/src/main/java/io/github/forkmaintainers/iceraven/components/PagedAddonInstallationDialogFragment.kt b/app/src/main/java/io/github/forkmaintainers/iceraven/components/PagedAddonInstallationDialogFragment.kt
new file mode 100644
index 000000000..df9448fa0
--- /dev/null
+++ b/app/src/main/java/io/github/forkmaintainers/iceraven/components/PagedAddonInstallationDialogFragment.kt
@@ -0,0 +1,309 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package io.github.forkmaintainers.iceraven.components
+
+import android.annotation.SuppressLint
+import android.app.Dialog
+import android.graphics.Bitmap
+import android.graphics.Color
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.ColorDrawable
+import android.graphics.drawable.GradientDrawable
+import android.os.Bundle
+import android.view.Gravity
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.view.Window
+import android.widget.Button
+import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.TextView
+import androidx.annotation.ColorRes
+import androidx.annotation.VisibleForTesting
+import androidx.appcompat.app.AppCompatDialogFragment
+import androidx.appcompat.widget.AppCompatCheckBox
+import androidx.core.content.ContextCompat
+import androidx.fragment.app.FragmentManager
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
+import mozilla.components.feature.addons.Addon
+import mozilla.components.feature.addons.R
+import mozilla.components.feature.addons.databinding.MozacFeatureAddonsFragmentDialogAddonInstalledBinding
+import mozilla.components.feature.addons.ui.translateName
+import mozilla.components.support.base.log.logger.Logger
+import mozilla.components.support.ktx.android.content.appName
+import mozilla.components.support.ktx.android.content.res.resolveAttribute
+import java.io.IOException
+
+@VisibleForTesting internal const val KEY_INSTALLED_ADDON = "KEY_ADDON"
+private const val KEY_DIALOG_GRAVITY = "KEY_DIALOG_GRAVITY"
+private const val KEY_DIALOG_WIDTH_MATCH_PARENT = "KEY_DIALOG_WIDTH_MATCH_PARENT"
+private const val KEY_CONFIRM_BUTTON_BACKGROUND_COLOR = "KEY_CONFIRM_BUTTON_BACKGROUND_COLOR"
+private const val KEY_CONFIRM_BUTTON_TEXT_COLOR = "KEY_CONFIRM_BUTTON_TEXT_COLOR"
+private const val KEY_CONFIRM_BUTTON_RADIUS = "KEY_CONFIRM_BUTTON_RADIUS"
+@VisibleForTesting internal const val KEY_ICON = "KEY_ICON"
+
+private const val DEFAULT_VALUE = Int.MAX_VALUE
+
+/**
+ * A dialog that shows [Addon] installation confirmation.
+ */
+// We have an extra "Lint" Android Studio linter pass that Android Components
+// where the original code came from doesn't. So we tell it to ignore us. Make
+// sure to keep up with changes in Android Components though.
+@SuppressLint("all")
+class PagedAddonInstallationDialogFragment : AppCompatDialogFragment() {
+ private val scope = CoroutineScope(Dispatchers.IO)
+ @VisibleForTesting internal var iconJob: Job? = null
+ private val logger = Logger("PagedAddonInstallationDialogFragment")
+ /**
+ * A lambda called when the confirm button is clicked.
+ */
+ var onConfirmButtonClicked: ((Addon, Boolean) -> Unit)? = null
+
+ /**
+ * Reference to the application's [PagedAddonCollectionProvider] to fetch add-on icons.
+ */
+ var addonCollectionProvider: PagedAddonCollectionProvider? = null
+
+ private val safeArguments get() = requireNotNull(arguments)
+
+ internal val addon get() = requireNotNull(safeArguments.getParcelable(KEY_ADDON))
+ private var allowPrivateBrowsing: Boolean = false
+
+ internal val confirmButtonRadius
+ get() =
+ safeArguments.getFloat(KEY_CONFIRM_BUTTON_RADIUS, DEFAULT_VALUE.toFloat())
+
+ internal val dialogGravity: Int
+ get() =
+ safeArguments.getInt(
+ KEY_DIALOG_GRAVITY,
+ DEFAULT_VALUE
+ )
+ internal val dialogShouldWidthMatchParent: Boolean
+ get() =
+ safeArguments.getBoolean(KEY_DIALOG_WIDTH_MATCH_PARENT)
+
+ internal val confirmButtonBackgroundColor
+ get() =
+ safeArguments.getInt(
+ KEY_CONFIRM_BUTTON_BACKGROUND_COLOR,
+ DEFAULT_VALUE
+ )
+
+ internal val confirmButtonTextColor
+ get() =
+ safeArguments.getInt(
+ KEY_CONFIRM_BUTTON_TEXT_COLOR,
+ DEFAULT_VALUE
+ )
+
+ override fun onStop() {
+ super.onStop()
+ iconJob?.cancel()
+ }
+
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ val sheetDialog = Dialog(requireContext())
+ sheetDialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
+ sheetDialog.setCanceledOnTouchOutside(true)
+
+ val rootView = createContainer()
+
+ sheetDialog.setContainerView(rootView)
+
+ sheetDialog.window?.apply {
+ if (dialogGravity != DEFAULT_VALUE) {
+ setGravity(dialogGravity)
+ }
+
+ if (dialogShouldWidthMatchParent) {
+ setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
+ // This must be called after addContentView, or it won't fully fill to the edge.
+ setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
+ }
+ }
+
+ return sheetDialog
+ }
+
+ private fun Dialog.setContainerView(rootView: View) {
+ if (dialogShouldWidthMatchParent) {
+ setContentView(rootView)
+ } else {
+ addContentView(
+ rootView,
+ LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.MATCH_PARENT,
+ LinearLayout.LayoutParams.MATCH_PARENT
+ )
+ )
+ }
+ }
+
+ @SuppressLint("InflateParams")
+ private fun createContainer(): View {
+ val rootView = LayoutInflater.from(requireContext()).inflate(
+ R.layout.mozac_feature_addons_fragment_dialog_addon_installed,
+ null,
+ false
+ )
+
+ val binding = MozacFeatureAddonsFragmentDialogAddonInstalledBinding.bind(rootView)
+
+ rootView.findViewById(R.id.title).text =
+ requireContext().getString(
+ R.string.mozac_feature_addons_installed_dialog_title,
+ addon.translateName(requireContext()),
+ requireContext().appName
+ )
+
+ val icon = safeArguments.getParcelable(KEY_ICON)
+ if (icon != null) {
+ binding.icon.setImageDrawable(BitmapDrawable(resources, icon))
+ } else {
+ iconJob = fetchIcon(addon, binding.icon)
+ }
+
+ val allowedInPrivateBrowsing = rootView.findViewById(R.id.allow_in_private_browsing)
+ allowedInPrivateBrowsing.setOnCheckedChangeListener { _, isChecked ->
+ allowPrivateBrowsing = isChecked
+ }
+
+ val confirmButton = rootView.findViewById