diff --git a/.github/workflows/android-build.yml b/.github/workflows/android-build.yml new file mode 100644 index 000000000..896978baf --- /dev/null +++ b/.github/workflows/android-build.yml @@ -0,0 +1,99 @@ +name: Android build +on: + push: + branches: + - fork + pull_request: + branches: + - fork +jobs: + run-build: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v2 + - name: Setup Java + uses: actions/setup-java@v1 + with: + java-version: 11 + - 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: assembleForkRelease -PversionName="$(git describe --tags HEAD)" + run-testDebug: + runs-on: ubuntu-latest + 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 + 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 + 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 + 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/.travis.yml b/.travis.yml new file mode 100644 index 000000000..cc4d361a5 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,13 @@ +language: android +dist: trusty +script: + - 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 + # Run tests + - ./gradlew -q testDebug 2>&1 + # Make sure a release build builds + - ./gradlew assembleForkRelease -PversionName="$(git describe --tags HEAD)" + diff --git a/README.md b/README.md index 2dfe98c8f..5f773be97 100644 --- a/README.md +++ b/README.md @@ -1,223 +1,106 @@ -# Firefox for Android +# Iceraven Browser! [![Build Status](https://travis-ci.org/fork-maintainers/iceraven-browser.svg?branch=fork)](https://travis-ci.org/fork-maintainers/iceraven-browser) ![Android build](https://github.com/fork-maintainers/iceraven-browser/workflows/Android%20build/badge.svg) -[![Task Status](https://github.taskcluster.net/v1/repository/mozilla-mobile/fenix/master/badge.svg)](https://github.taskcluster.net/v1/repository/mozilla-mobile/fenix/master/latest) -[![codecov](https://codecov.io/gh/mozilla-mobile/fenix/branch/master/graph/badge.svg)](https://codecov.io/gh/mozilla-mobile/fenix) +Definitely not brought to you by Mozilla! -Fenix (internal codename) is the all-new Firefox for Android browser, based on [GeckoView](https://mozilla.github.io/geckoview/) and [Mozilla Android Components](https://mozac.org/). +Iceraven Browser is a web browser for Android, based on [Mozilla's Fenix version of Firefox](https://github.com/mozilla-mobile/fenix/), [GeckoView](https://mozilla.github.io/geckoview/) and [Mozilla Android Components](https://mozac.org/). -Get it on Google Play +Our goal is to be a close fork of the new Firefox for Android that seeks to provide users with more options, more opportunities to customize (including a broad extension library), and more information about the pages they visit and how their browsers are interacting with those pages. -** Note: The team is currently experiencing heavy triage and review load, so when triaging issues, we will mainly be looking to identify [S1 (high severity)](https://github.com/mozilla-mobile/fenix/labels/S1) issues. See our triage process [here](https://github.com/mozilla-mobile/fenix/wiki/Triage-Process). Please be patient if you don't hear back from us immediately on your issue! ** +Notable features include: + * `about:config` support + * The ability to *attempt* to install a much longer list of add-ons than Mozilla's Fenix version of Firefox accepts. Currently the browser queries [this AMO collection](https://addons.mozilla.org/en-US/firefox/collections/16201230/What-I-want-on-Fenix/) **Most of them will not work**, because they depend on code that Mozilla is still working on writing in `android-components`, but you may attempt to install them. If you don't see an add-on you want, you can [request it](https://github.com/fork-maintainers/iceraven-browser/issues/new). + * **No warranties or guarantee of security or updates**. Binaries are currently are manually built and are not meaningfully signed. Why should you trust random people on the Internet to provide your web browser, one of the most important pieces of software you use? Iceraven Browser could not exist without the hardworking folks at the Mozilla Corporation who work on the Mozilla Android Components and Firefox projects, but it is not a Mozilla product, and is not provided, endorsed, vetted, approved, or secured by Mozilla. -## Getting Involved - -Please read the [Community Participation Guidelines](https://www.mozilla.org/en-US/about/governance/policies/participation/) and the [Bugzilla Etiquette guidelines](https://bugzilla.mozilla.org/page.cgi?id=etiquette.html) before filing an issue. This is our professional working environment as much as it is our bug tracker, and we want to keep our workspace clean and healthy. - -* [Guide to Contributing](https://github.com/mozilla-mobile/shared-docs/blob/master/android/CONTRIBUTING.md) (**New contributors start here!**) - -* Browse our [current Issues](https://github.com/mozilla-mobile/fenix/issues), or [file a security issue][sec issue]. - -* Matrix: [#fenix:mozilla.org channel](https://chat.mozilla.org/#/room/#fenix:mozilla.org) (**We're available Monday-Friday, GMT and PST working hours**). Related channels: - * [#mobile-test-eng:mozilla.org channel](https://chat.mozilla.org/#/room/#mobile-test-eng:mozilla.org): for UI test automation - * [#perf-android-frontend:mozilla.org channel](https://chat.mozilla.org/#/room/#perf-android-frontend:mozilla.org): for front-end (JVM) performance of Android apps - * [#android-tips:mozilla.org channel](https://chat.mozilla.org/#/room/#android-tips:mozilla.org): for tips on Android development - -* Check out the [project wiki](https://github.com/mozilla-mobile/fenix/wiki) for more information. - -* Localization happens on [Pontoon](https://pontoon.mozilla.org/projects/android-l10n/). Please get in touch with delphine (at) mozilla (dot) com directly for more information. - -**Beginners!** - Watch out for [Issues with the "Good First Issue" label](https://github.com/mozilla-mobile/fenix/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22). These are easy bugs that have been left for first timers to have a go, get involved and make a positive contribution to the project! - - -## I want to open a Pull Request! - -We encourage you to participate in this open source project. We love Pull Requests, Bug Reports, ideas, (security) code reviews or any other kind of positive contribution. - -Since we are a small team, however, **we do not have the bandwidth to review unsolicited PRs**. Please follow our [Pull Request guidelines](https://github.com/mozilla-mobile/shared-docs/blob/master/android/CONTRIBUTING_code.md#creating-a-pull-request), or **we may close the PR**. - -To make it easier to review, we have these PR requirements: - -* Every PR must have **exactly** one issue associated with it. -* Write a clear explanation of what the code is doing when opening the pull request, and optionally add comments to the PR. -* Make sure there are tests - or ask for help on how the code should be tested in the Issue! -* Keep PRs small and to the point. For extra code-health changes, either file a separate issue, or make it a separate PR that can be easily reviewed. -* Use micro-commits. This makes it easier and faster to review. -* Add a screenshot for UX changes (this is part of the PR checklist) - -As a small team, we have to prioritize our work, and reviewing PRs takes time. We receive lots of PRs every day, so if you can keep your PRs small, it helps our small team review and merge code faster, minimizing stale code. - - -Keep in mind that the team is very overloaded, so PRs sometimes wait -for a *very* long time. However this is not for lack of interest, but -because we find ourselves in a constant need to prioritize -certain issues/PRs over others. If you think your issue/PR is very important, -try to popularize it by getting other users to comment and share their point of view. - -## I want to file an issue! - -Great! We encourage you to participate in this open source project. We love Pull Requests, Bug Reports, ideas, (security) code reviews or any other kind of positive contribution. - -To make it easier to triage, we have these issue requirements: - -* Please do your best to search for duplicate issues before filing a new issue so we can keep our issue board clean. -* Every issue should have **exactly** one bug/feature request described in it. Please do not file meta feedback list tickets as it is difficult to parse them and address their individual points. -* Feature Requests are better when they’re open-ended instead of demanding a specific solution -ie “I want an easier way to do X” instead of “add Y” -* Issues are not the place to go off topic or debate. If you have questions, please join the [#fenix:mozilla.org channel](https://chat.mozilla.org/#/room/#fenix:mozilla.org). -* Please always remember our [Community Participation Guidelines](https://www.mozilla.org/en-US/about/governance/policies/participation/) -* Please do not tag specific team members to try to get your issue looked at faster. We have a triage process that will tag and label issues correctly in due time. If you think an issue is very severe, you can ask about it in Matrix. - -Please keep in mind that even though a feature you have in mind may seem like a small ask, as a small team, we have to prioritize our planned work and every new feature adds complexity and maintenance and may take up design, research, marketing, product, and engineering time. We appreciate everyone’s passion but we will not be able to incorporate every feature request or even fix every bug. That being said, just because we haven't replied, doesn't mean we don't care about the issue, please be patient with our response times as we're very busy. - -## Build Instructions - -Pre-requisites: -* Android SDK -* To run command line tools, you'll need to configure Java: see [our how-to guide](https://github.com/mozilla-mobile/shared-docs/blob/master/android/configure_java.md). - -1. Clone or Download the repository: - - ```shell - git clone https://github.com/mozilla-mobile/fenix - ``` +In addition, we intend to try to cut down on telemetry and proprietary code to as great of an extent as possible as long as doing so does not compromise the user experience or make the fork too hard to maintain. Right now, webelieve that no telemetry should be being sent to Mozilla anymore, but we cannot guarantee this; data may still be sent. **If you catch the app sending data to Mozilla, Adjust, Leanplum, Firebase, or any other such service, please open an issue!** Presumably data that reaches Mozilla is governed by Mozilla's privacy policy, but as Iceraven Browser is, again **not a Mozilla product**, we can make no promises. -2. **Import** the project into Android Studio **or** build on the command line: +Iceraven Browser combines the power of Fenix (of which we are a fork) and the spirit of Fennec, with a respectful nod toward the grand tradition of Netscape Navigator, from which all Gecko-based projects came, including the earliest of our predecessors, the old Mozilla Phoenix and Mozilla Firefox desktop browsers. - ```shell - ./gradlew clean app:assembleDebug - ``` +That said, Iceraven Browser is an independent all-volunteer project, and has no affiliation with Netscape, Netscape Navigator, Mozilla, Mozilla Firefox, Mozila Phoenix, Debian, Debian Iceweasel, Parabola GNU/Linux-libre Iceweasel, America Online, or Verizon, among others. :) Basically, if you don't like the browser, it's not their fault. :) - If this errors out, make sure that you have an `ANDROID_SDK_ROOT` environment - variable pointing to the right path. +## Installation -3. Make sure to select the correct build variant in Android Studio. See the next section. +[**Download APKs from the Releases Page**](https://github.com/fork-maintainers/iceraven-browser/releases) -### Build Variants -For general development, we recommend the **debug** build variant. Here's an explanation of each variant: +## Building -- **debug**: the default for developers, similar to most other Android apps. It is debuggable, uses a Nightly GeckoView with debug symbols, adds tools like LeakCanary for troublingshooting, and does not strip unused code. -- **nightly**: what we ship to the Firefox Nightly channel, using GeckoView Nightly. -- **beta**: what we ship to the Firefox Beta channel, using GeckoView Beta. It is more stable than nightly. -- **release**: what we ship as Firefox for Android, using GeckoView Release. It is the most stable. +1. Set up the environment. We need the Android SDK at `$ANDROID_SDK_ROOT` and a Java JDK at `$JAVA_HOME` that isn't the Ubuntu Java 8 one. We want environment variables that look something like: -nightly, beta, and release are unsigned and `debuggable=false` by default. If -you want these variants to be: -- automatically signed, see [Automatically signing release builds](#automatically-sign-release-builds) -- `debuggable=true`, see [Building debuggable release variants](#building-debuggable-release-variants) - -#### Performance Build Variants -For accurate performance measurements, read this section! - -To analyze performance during **local development** build a production variant locally (this could either be the Nightly, beta or release). Otherwise, you could also grab a pre-existing APK if you don't need to test some local changes. Then, use the Firefox profiler to profile what you need! - -For more information on how to use the profiler or how to use the build, refer to this [how to measure performance with the build](https://wiki.mozilla.org/Performance/How_to_get_started_on_Fenix) - -If you want to run **performance tests/benchmarks** in automation or locally use a production build since it is much closer in behavior compared to what users see in the wild. - -Before you can install any release builds, **You will need to sign production build variants:** see [Automatically signing release builds](#automatically-sign-release-builds) for details. - -##### Known disabled-by-default features -Some features are disabled by default when Fenix is built locally. This can be problematic at times for checking performance since you might want to know how your code behaves with those features. -The known features that are disabled by default are: -- Sentry -- Leanplum -- Adjust -- Mozilla Location Services (also known as MLS) -- Firebase Push Services -- Telemetry (only disabled by default in debug builds) - -## Pre-push hooks -To reduce review turn-around time, we'd like all pushes to run tests locally. We'd -recommend you use our provided pre-push hook in `config/pre-push-recommended.sh`. -Using this hook will guarantee your hook gets updated as the repository changes. -This hook tries to run as much as possible without taking too much time. - -Before you can run the hook, you'll need to configure Java properly because it relies on command line tools: see -[our how-to guide](https://github.com/mozilla-mobile/shared-docs/blob/master/android/configure_java.md). - -To add it on Mac/Linux, run this command from the project root: ```sh -ln -s ../../config/pre-push-recommended.sh .git/hooks/pre-push -``` -or for Windows run this command using the Command Prompt with administrative privileges: -```sh -mklink .git\hooks\pre-push ..\..\config\pre-push-recommended.sh -``` -or using PowerShell: -```sh -New-Item -ItemType SymbolicLink -Path .git\hooks\pre-push -Value (Resolve-Path config\pre-push-recommended.sh) +# Where does our system install the JDK? This is the right path for the Ubuntu Java 11 JDK, if it is installed. +export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64 +# Where did we install the Android SDK? +export ANDROID_SDK_ROOT=$HOME/android-sdk/android-sdk-linux/ ``` -To push without running the pre-push hook (e.g. doc updates): +If we don't have the Android SDK, we can install it thusly on Linux: + ```sh -git push --no-verify +mkdir -p $HOME/android-sdk/android-sdk-linux +cd $HOME/android-sdk/android-sdk-linux +mkdir -p licenses +echo "8933bad161af4178b1185d1a37fbf41ea5269c55" >> licenses/android-sdk-license +echo "d56f5187479451eabf01fb78af6dfcb131a6481e" >> licenses/android-sdk-license +echo "24333f8a63b6825ea9c5514f83c2829b004d1fee" >> licenses/android-sdk-license +mkdir cmdline-tools +cd cmdline-tools +wget "$(curl -s https://developer.android.com/studio | grep -oP "https://dl.google.com/android/repository/commandlinetools-linux-[0-9]+_latest.zip")" +unzip commandlinetools-linux-*_latest.zip +cd .. ``` -Note: If while pushing you encounter this error "Could not initialize class org.codehaus.groovy.runtime.InvokerHelper" and are currently on Java14 then downgrading your Java version to Java13 or lower can resolve the issue - -Steps to downgrade Java Version on Mac with Brew: -1. Install Homebrew (https://brew.sh/) -2. run ```brew update``` -3. To uninstall your current java version, run ```sudo rm -fr /Library/Java/JavaVirtualMachines/``` -4. run ```brew tap homebrew/cask-versions``` -5. run ```brew search java``` -6. If you see java11, then run ```brew install java11``` -7. Verify java-version by running ```java -version``` +2. Clone the project. -## local.properties helpers -You can speed up local development by setting a few helper flags available in `local.properties`. Some flags will make it easy to -work across multiple layers of the dependency stack - specifically, with android-components, geckoview or application-services. +```sh +git clone https://github.com/fork-maintainers/iceraven-browser +``` -### Automatically sign release builds -To sign your release builds with your debug key automatically, add the following to `/local.properties`: +4. Go inside `iceraven-browser`. That's where the build is coordinated from. ```sh -autosignReleaseWithDebugKey +cd iceraven-browser ``` -With this line, release build variants will automatically be signed with your debug key (like debug builds), allowing them to be built and installed directly through Android Studio or the command line. +5. Configure the project. We need to set the release builds to be signed with the debug key, because proper code signing isn't set up yet and the completely unsigned APKs that are produced by default cannot be installed. -This is helpful when you're building release variants frequently, for example to test feature flags and or do performance analyses. - -### Building debuggable release variants +```sh +echo "autosignReleaseWithDebugKey=" >>local.properties +``` -Nightly, Beta and Release variants are getting published to Google Play and therefore are not debuggable. To locally create debuggable builds of those variants, add the following to `/local.properties`: +6. Build the project. To build the Iceraven-branded release APKs, you can do: ```sh -debuggable +./gradlew assembleForkRelease -PversionName="$(git describe --tags HEAD)" ``` -### Setting raptor manifest flag +The APKs will show up in `app/build/outputs/apk/forkRelease/`. -To set the raptor manifest flag in Nightly, Beta and Release variants, add the following to `/local.properties`: +## Getting Involved -```sh -raptorEnabled -``` +This is an all-volunteer project. No one is getting paid (at least not by the project itself.). -### Auto-publication workflow for android-components and application-services -If you're making changes to these projects and want to test them in Fenix, auto-publication workflow is the fastest, most reliable -way to do that. +Therefore, everyone should feel free to open issues and pull requests. Join the club! -In `local.properties`, specify a relative path to your local `android-components` and/or `application-services` checkouts. E.g.: -- `autoPublish.android-components.dir=../android-components` -- `autoPublish.application-services.dir=../application-services` +Developers are especially welcome, wanted, and needed. -Once these flags are set, your Fenix builds will include any local modifications present in these projects. +## I want to open a Pull Request! -See a [demo of auto-publication workflow in action](https://www.youtube.com/watch?v=qZKlBzVvQGc). +We encourage you to participate in this open source project. We love Pull Requests, Bug Reports, ideas, (security) code reviews or any other kind of positive contribution. -### GeckoView -Specify a relative path to your local `mozilla-central` checkout via `dependencySubstitutions.geckoviewTopsrcdir`, -and optional a path to m-c object directory via `dependencySubstitutions.geckoviewTopobjdir`. +## I want to file an issue! -If these are configured, local builds of GeckoView will be used instead of what's configured in Dependencies.kt. -For more details, see https://firefox-source-docs.mozilla.org/mobile/android/geckoview/contributor/geckoview-quick-start.html#include-geckoview-as-a-dependency +Great! We encourage you to participate in this open source project. We love Pull Requests, Bug Reports, ideas, (security) code reviews or any other kind of positive contribution. + +To make it easier to triage, we have these issue requirements: + +* Please do your best to search for duplicate issues before filing a new issue so we can keep our issue board clean. +* Every issue should have **exactly** one bug/feature request described in it. Please do not file meta feedback list tickets as it is difficult to parse them and address their individual points. +* Feature Requests are better when they’re open-ended instead of demanding a specific solution -ie “I want an easier way to do X” instead of “add Y” +* Issues are not the place to go off topic or debate. +* While we do not yet have Community Participation Guidelines of our own, we ask that you show respect to everyone and treat others as you would like to be treated. Behavior that would violate [Mozilla's Community Participation Guidelines](https://www.mozilla.org/en-US/about/governance/policies/participation/) is almost certainly unwelcome. However, as a small project without community managers, we cannot promise prompt and consistent enforcement. -## License +Please keep in mind that even though a feature you have in mind may seem like a small ask, as a small team, we have to prioritize our planned work and every new feature adds complexity and maintenance and may take up design, research, product, and engineering time. We appreciate everyone’s passion but we will not be able to incorporate every feature request or even fix every bug. That being said, just because we haven't replied, doesn't mean we don't care about the issue, please be patient with our response times as we're very busy. 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/ - -[sec issue]: https://bugzilla.mozilla.org/enter_bug.cgi?assigned_to=nobody%40mozilla.org&bug_ignored=0&bug_severity=normal&bug_status=NEW&cf_fx_iteration=---&cf_fx_points=---&component=Security%3A%20Android&contenttypemethod=list&contenttypeselection=text%2Fplain&defined_groups=1&flag_type-4=X&flag_type-607=X&flag_type-791=X&flag_type-800=X&flag_type-803=X&flag_type-936=X&flag_type-937=X&form_name=enter_bug&groups=mobile-core-security&maketemplate=Remember%20values%20as%20bookmarkable%20template&op_sys=Unspecified&priority=--&product=Fenix&rep_platform=Unspecified&target_milestone=---&version=unspecified diff --git a/app/build.gradle b/app/build.gradle index dfcc663d9..fa6fb01f5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -21,7 +21,7 @@ import static org.gradle.api.tasks.testing.TestResult.ResultType android { compileSdkVersion Config.compileSdkVersion defaultConfig { - applicationId "org.mozilla" + applicationId "io.github.forkmaintainers" minSdkVersion Config.minSdkVersion targetSdkVersion Config.targetSdkVersion versionCode 1 @@ -31,6 +31,7 @@ android { testInstrumentationRunnerArguments clearPackageData: 'true' resValue "bool", "IS_DEBUG", "false" buildConfigField "boolean", "USE_RELEASE_VERSIONING", "false" + buildConfigField "String", "AMO_ACCOUNT", "\"mozilla\"" buildConfigField "String", "AMO_COLLECTION", "\"3204bb44a6ef44d39ee34917f28055\"" def deepLinkSchemeValue = "fenix-dev" buildConfigField "String", "DEEP_LINK_SCHEME", "\"$deepLinkSchemeValue\"" @@ -105,6 +106,34 @@ android { "deepLinkScheme": deepLinkSchemeValue ] } + 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_ACCOUNT", "\"16201230\"" + buildConfigField "String", "AMO_COLLECTION", "\"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_ACCOUNT", "\"16201230\"" + buildConfigField "String", "AMO_COLLECTION", "\"What-I-want-on-Fenix\"" + } + } aaptOptions { @@ -145,6 +174,13 @@ android { java.srcDirs = ['src/migration/java', 'src/geckoRelease/java'] manifest.srcFile "src/migration/AndroidManifest.xml" } + forkDebug { + java.srcDirs = ['src/geckoNightly/java'] + } + forkRelease { + // No migration needed for fork + java.srcDirs = ['src/geckoRelease/java'] + } } splits { @@ -195,7 +231,7 @@ android.applicationVariants.all { variant -> def isDebug = variant.buildType.resValues['IS_DEBUG']?.value ?: false def useReleaseVersioning = variant.buildType.buildConfigFields['USE_RELEASE_VERSIONING']?.value ?: false - def versionName = Config.releaseVersionName(project) + def versionName = Config.releaseVersionName(project) == "" ? Config.generateDebugVersionName() : Config.releaseVersionName(project) println("----------------------------------------------") println("Variant name: " + variant.name) @@ -204,11 +240,14 @@ 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 // builds. - + + println("Version Name: " + versionName) + variant.outputs.each { output -> def abi = output.getFilter(OutputFile.ABI) // We use the same version code generator, that we inherited from Fennec, across all channels - even on @@ -319,10 +358,12 @@ apply plugin: "org.mozilla.telemetry.glean-gradle-plugin" dependencies { debugImplementation Deps.mozilla_browser_engine_gecko_nightly + forkDebugImplementation Deps.mozilla_browser_engine_gecko_nightly nightlyImplementation Deps.mozilla_browser_engine_gecko_nightly betaImplementation Deps.mozilla_browser_engine_gecko_beta releaseImplementation Deps.mozilla_browser_engine_gecko_release + forkReleaseImplementation Deps.mozilla_browser_engine_gecko_release implementation Deps.kotlin_stdlib implementation Deps.kotlin_coroutines @@ -334,8 +375,6 @@ dependencies { implementation Deps.sentry - implementation Deps.leanplum_core - implementation Deps.leanplum_fcm implementation Deps.mozilla_concept_engine implementation Deps.mozilla_concept_menu @@ -415,9 +454,9 @@ dependencies { implementation Deps.mozilla_ui_widgets implementation Deps.mozilla_lib_crash - implementation Deps.mozilla_lib_push_firebase implementation Deps.mozilla_lib_dataprotect debugImplementation Deps.leakcanary + forkDebugImplementation Deps.leakcanary implementation Deps.androidx_legacy implementation Deps.androidx_biometric @@ -438,12 +477,6 @@ dependencies { implementation Deps.lottie - 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 // Removed pending AndroidX fixes @@ -531,6 +564,9 @@ if (project.hasProperty("coverage")) { debug { testCoverageEnabled true } + forkDebug { + testCoverageEnabled true + } } } } 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..7f5c86762 --- /dev/null +++ b/app/src/forkDebug/java/org/mozilla/fenix/DebugFenixApplication.kt @@ -0,0 +1,28 @@ +/* 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 +import org.mozilla.fenix.ext.resetPoliciesAfter + +class DebugFenixApplication : FenixApplication() { + + override fun setupLeakCanary() { + val isEnabled = StrictMode.allowThreadDiskReads().resetPoliciesAfter { + 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/ic_launcher-playstore.png b/app/src/forkRelease/ic_launcher-playstore.png new file mode 100644 index 000000000..ae8c80770 Binary files /dev/null and b/app/src/forkRelease/ic_launcher-playstore.png differ 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..1392eb40c 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..90823d445 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..ba46cbd51 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..750c2efcd 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..feb6225b2 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..76080b671 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..1d2db1807 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..4fedbf950 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..bc9fa8924 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..28fd06676 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..b9d6f3078 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/ic_launcher-web.png b/app/src/forkRelease/res/ic_launcher-web.png new file mode 100644 index 000000000..fec0c7793 Binary files /dev/null and b/app/src/forkRelease/res/ic_launcher-web.png differ 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/mipmap-hdpi/ic_launcher.png b/app/src/forkRelease/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..ceddde289 Binary files /dev/null and b/app/src/forkRelease/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/src/forkRelease/res/mipmap-hdpi/ic_launcher_round.png b/app/src/forkRelease/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 000000000..4020f9e7e Binary files /dev/null and b/app/src/forkRelease/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/app/src/forkRelease/res/mipmap-mdpi/ic_launcher.png b/app/src/forkRelease/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..ceddde289 Binary files /dev/null and b/app/src/forkRelease/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/src/forkRelease/res/mipmap-mdpi/ic_launcher_round.png b/app/src/forkRelease/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 000000000..4020f9e7e Binary files /dev/null and b/app/src/forkRelease/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/app/src/forkRelease/res/mipmap-xhdpi/ic_launcher.png b/app/src/forkRelease/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..ceddde289 Binary files /dev/null and b/app/src/forkRelease/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/src/forkRelease/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/forkRelease/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 000000000..4020f9e7e Binary files /dev/null and b/app/src/forkRelease/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/app/src/forkRelease/res/mipmap-xxhdpi/ic_launcher.png b/app/src/forkRelease/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..ceddde289 Binary files /dev/null and b/app/src/forkRelease/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/src/forkRelease/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/forkRelease/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 000000000..4020f9e7e Binary files /dev/null and b/app/src/forkRelease/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/app/src/forkRelease/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/forkRelease/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..ceddde289 Binary files /dev/null and b/app/src/forkRelease/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/app/src/forkRelease/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/forkRelease/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 000000000..4020f9e7e Binary files /dev/null and b/app/src/forkRelease/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/app/src/forkRelease/res/values/colors.xml b/app/src/forkRelease/res/values/colors.xml new file mode 100644 index 000000000..60b6ba1df --- /dev/null +++ b/app/src/forkRelease/res/values/colors.xml @@ -0,0 +1,7 @@ + + + + #ffffffff + 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/geckoBeta/java/org/mozilla/fenix/engine/GeckoProvider.kt b/app/src/geckoBeta/java/org/mozilla/fenix/engine/GeckoProvider.kt index 1bebe0c5c..eb13a10e4 100644 --- a/app/src/geckoBeta/java/org/mozilla/fenix/engine/GeckoProvider.kt +++ b/app/src/geckoBeta/java/org/mozilla/fenix/engine/GeckoProvider.kt @@ -42,7 +42,7 @@ object GeckoProvider { .crashHandler(CrashHandlerService::class.java) .telemetryDelegate(GeckoAdapter()) .contentBlocking(policy.toContentBlockingSetting()) - .aboutConfigEnabled(Config.channel.isBeta) + .aboutConfigEnabled(true) .debugLogging(Config.channel.isDebug) .build() diff --git a/app/src/geckoRelease/java/org/mozilla/fenix/engine/GeckoProvider.kt b/app/src/geckoRelease/java/org/mozilla/fenix/engine/GeckoProvider.kt index ef75ce688..a01593bb7 100644 --- a/app/src/geckoRelease/java/org/mozilla/fenix/engine/GeckoProvider.kt +++ b/app/src/geckoRelease/java/org/mozilla/fenix/engine/GeckoProvider.kt @@ -52,7 +52,7 @@ object GeckoProvider { .crashHandler(CrashHandlerService::class.java) .telemetryDelegate(GeckoAdapter()) .contentBlocking(policy.toContentBlockingSetting()) - .aboutConfigEnabled(Config.channel.isBeta) + .aboutConfigEnabled(true) .debugLogging(Config.channel.isDebug) .build() 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..e219144db --- /dev/null +++ b/app/src/main/java/com/adjust/sdk/Adjust.java @@ -0,0 +1,40 @@ +/* + * 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) { + } +} 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..3924681c4 --- /dev/null +++ b/app/src/main/java/com/google/android/gms/ads/identifier/AdvertisingIdClient.java @@ -0,0 +1,41 @@ +/* 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; +import com.google.android.gms.common.GooglePlayServicesNotAvailableException; +import com.google.android.gms.common.GooglePlayServicesRepairableException; + + +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) throws GooglePlayServicesNotAvailableException, GooglePlayServicesRepairableException { + return new Info(); + } + +} diff --git a/app/src/main/java/com/google/android/gms/common/GooglePlayServicesNotAvailableException.java b/app/src/main/java/com/google/android/gms/common/GooglePlayServicesNotAvailableException.java new file mode 100644 index 000000000..d401bd931 --- /dev/null +++ b/app/src/main/java/com/google/android/gms/common/GooglePlayServicesNotAvailableException.java @@ -0,0 +1,12 @@ +/* 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.common; + +public class GooglePlayServicesNotAvailableException extends Exception { + + public GooglePlayServicesNotAvailableException(int arg1) { + } + +} diff --git a/app/src/main/java/com/google/android/gms/common/GooglePlayServicesRepairableException.java b/app/src/main/java/com/google/android/gms/common/GooglePlayServicesRepairableException.java new file mode 100644 index 000000000..5786ca212 --- /dev/null +++ b/app/src/main/java/com/google/android/gms/common/GooglePlayServicesRepairableException.java @@ -0,0 +1,10 @@ +/* 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.common; + +public class GooglePlayServicesRepairableException extends Exception { + public GooglePlayServicesRepairableException(int arg1, String arg2, Object arg3) { + } +} 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..ed808e911 --- /dev/null +++ b/app/src/main/java/com/leanplum/Leanplum.java @@ -0,0 +1,91 @@ +/* + * 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) { + } +} 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..57be8f920 --- /dev/null +++ b/app/src/main/java/io/github/forkmaintainers/iceraven/components/PagedAddonCollectionProvider.kt @@ -0,0 +1,360 @@ +/* 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 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 DEFAULT_COLLECTION_ACCOUNT = "mozilla" +internal const val DEFAULT_COLLECTION_NAME = "7e8d6dc651b54ab385fb8791bf9dac" +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 collectionAccount The account owning the collection to access, defaults + * to [DEFAULT_COLLECTION_ACCOUNT]. + * @property collectionName The name of the collection to access, defaults + * to [DEFAULT_COLLECTION_NAME]. + * @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 var collectionAccount: String = DEFAULT_COLLECTION_ACCOUNT, + private var collectionName: String = DEFAULT_COLLECTION_NAME, + private val maxCacheAgeInMinutes: Long = -1 +) : AddonsProvider { + + private val logger = Logger("PagedAddonCollectionProvider") + + private val diskCacheLock = Any() + + fun setCollectionAccount(account: String) { + collectionAccount = account + } + + fun setCollectionName(collection: String) { + collectionName = collection + } + + /** + * 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. + * @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?): List { + val cachedAddons = if (allowCache && !cacheExpired(context)) { + readFromDiskCache() + } else { + null + } + + if (cachedAddons != null) { + return cachedAddons + } else { + 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) { + synchronized(diskCacheLock) { + getCacheFile(context).writeString { collectionResponse } + } + } + + @VisibleForTesting + internal fun readFromDiskCache(): List? { + 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 { + return File(context.filesDir, COLLECTION_FILE_NAME.format(collectionAccount, collectionName)) + } + + fun deleteCacheFile(context: Context): Boolean { + 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")) { + Addon( + id = getSafeString("guid"), + authors = getAuthors(), + categories = getCategories(), + createdAt = getSafeString("created"), + updatedAt = getSafeString("last_updated"), + downloadUrl = 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.getDownloadUrl(): String { + return (getJSONObject("current_version") + .optJSONArray("files") + ?.getJSONObject(0)) + ?.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..8ce89ec23 --- /dev/null +++ b/app/src/main/java/io/github/forkmaintainers/iceraven/components/PagedAddonInstallationDialogFragment.kt @@ -0,0 +1,301 @@ +/* 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.android.synthetic.main.mozac_feature_addons_fragment_dialog_addon_installed.view.* +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.ui.translatedName +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. + */ +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 + ) + + rootView.findViewById(R.id.title).text = + requireContext().getString( + R.string.mozac_feature_addons_installed_dialog_title, + addon.translatedName, + requireContext().appName + ) + + val icon = safeArguments.getParcelable(KEY_ICON) + if (icon != null) { + rootView.icon.setImageDrawable(BitmapDrawable(resources, icon)) + } else { + iconJob = fetchIcon(addon, rootView.icon) + } + + val allowedInPrivateBrowsing = rootView.findViewById(R.id.allow_in_private_browsing) + allowedInPrivateBrowsing.setOnCheckedChangeListener { _, isChecked -> + allowPrivateBrowsing = isChecked + } + + val confirmButton = rootView.findViewById