diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 000000000..55edfe24f
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,12 @@
+version: 2
+updates:
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "daily"
+ target-branch: "master"
+ - package-ecosystem: "gradle"
+ directory: "/"
+ schedule:
+ interval: "daily"
+ target-branch: "master"
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 000000000..73c0dc98d
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,18 @@
+name: Build application
+
+on: [pull_request, push]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v6
+ - name: Set up JDK 25
+ uses: actions/setup-java@v5
+ with:
+ distribution: 'temurin'
+ java-version: 25
+ cache: gradle
+ - name: Build with Gradle
+ run: ./gradlew build --no-daemon
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
deleted file mode 100644
index f1db7deb1..000000000
--- a/.github/workflows/release.yml
+++ /dev/null
@@ -1,37 +0,0 @@
----
-on:
- push:
- # Uncomment to test against a branch
- #branches:
- # - ci
- tags:
- - 'v*'
-jobs:
- create_release:
- name: Create Github release
- runs-on: ubuntu-latest
- permissions:
- contents: write
- steps:
- - name: Get version from tag
- id: get_version
- run: |
- if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
- version=${GITHUB_REF#refs/tags/v}
- else
- version=0.0.0.${GITHUB_REF#refs/heads/}
- fi
- echo "version=${version}" >> "${GITHUB_OUTPUT}"
-
- - name: Check out repository
- uses: actions/checkout@v3
-
- - name: Create release
- uses: softprops/action-gh-release@v1
- with:
- token: ${{ secrets.GITHUB_TOKEN }}
- tag_name: v${{ steps.get_version.outputs.version }}
- name: Version ${{ steps.get_version.outputs.version }}
- body_path: RELEASE.md
- draft: true
- prerelease: false
diff --git a/.github/workflows/validate-gradle-wrapper.yml b/.github/workflows/validate-gradle-wrapper.yml
new file mode 100644
index 000000000..5481f65f7
--- /dev/null
+++ b/.github/workflows/validate-gradle-wrapper.yml
@@ -0,0 +1,11 @@
+name: Validate Gradle Wrapper
+
+on: [pull_request, push]
+
+jobs:
+ validation:
+ name: Validation
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v6
+ - uses: gradle/wrapper-validation-action@v5
diff --git a/.gitignore b/.gitignore
index faf530b2d..a7c60a12c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,10 +1,7 @@
-*.iml
-.gradle
+/.gradle
+/.kotlin
/local.properties
-/.idea/
+/.idea
.DS_Store
/build
-/captures
-.externalNativeBuild
-.cxx
-local.properties
+/keystore.properties
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3582c0952..0358e1eef 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,320 +1,3 @@
-### Version 1.39
-
-* Update Russian translations (PR: #277, @bogachenko)
-* Add Simplified Chinese translations (PR: #283, @Yee2)
-
-### Version 1.38
-
-* Update all dependencies (PR: #266, #272, @PatrykMis)
-* Mark quick settings tile as toggleable for accessibility (PR: #270, @PatrykMis)
-* Add support for Android 13's per-app language preferences (PR: #271, @PatrykMis)
-* Fix crash when changing the output directory if the previous output directory was associated with a cloud provider app that is no longer installed (PR: #273, @chenxiaolong)
-* Show friendly path name instead of `content://` when the output directory points to a cloud provider app (PR: #274, @chenxiaolong)
-
-### Version 1.37
-
-* Fix custom filename templates breaking after version 1.35 in release builds (Issue: #260, PR: #261, @chenxiaolong)
-
-### Version 1.36
-
-* Fix loss of file extension when the output file needs to be renamed (PR: #259, @chenxiaolong)
-
-### Version 1.35
-
-* Fix missing BCR app when doing a direct (non-Magisk module) installation (Issue: #253, PR: #254, @chenxiaolong)
- * This bug was introduced in version 1.34 and was caused by an oversight when adding the workaround for overlayfs.
-* Work around absurdly slow SAF (Android Storage Access Framework) on some devices (Issue: #252, PR: #257, @chenxiaolong)
- * This fixes audio being chopped off the beginning of the call recording. Some devices' SAF implementations are slow to the point where checking the existence of a file may take upwards of 8 seconds (vs. 2ms with native file access).
- * This only affected users who picked a custom output directory. The default output directory uses native file access instead of SAF.
-* Fix caller ID and contact name potentially ending up in the log file if they change during the middle of a call (PR: #258, @chenxiaolong)
-
-### Version 1.34
-
-* Write `crash.log` to output directory if BCR crashes outside of the scope of a phone call (Issue: #243, PR: #245, @chenxiaolong)
-* Set default notification importance to high for the persistent notification during a all (Issue: #248, PR: #249, @chenxiaolong)
- * This makes it easier to access the pause/resume button in the notification.
- * This change only affects new installs and the user's notification preferences in Android's settings will always take precedence.
-* Work around broken NFC and possible bootloops on MIUI when `/system` contains overlayfs mount points (Issue: #242, #246, PR: #250, @chenxiaolong)
- * This is only a workaround for a bug in Magisk's mount logic. The actual Magisk bug will be fixed by: https://github.com/topjohnwu/Magisk/pull/6588.
-
-### Version 1.33
-
-* Fix crash caused by a workaround for a old material3 library bug that has since been fixed (Issue: #240, PR: #241, @chenxiaolong)
-
-### Version 1.32
-
-* Add Hebrew translations (PR: #232, @Mosheh65)
-
-### Version 1.31
-
-* For the OGG/Opus bitrate option, reduce the number of steps between 6 kbps and 510 kbps from 253 to 25 (Issue: #237, PR: #239, @chenxiaolong)
-
-Non-user-facing changes:
-
-* Updated all dependencies (PR: #238, @chenxiaolong)
-
-Signing changes:
-
-* Switch from GPG signing to SSH signing for new release zips, git commits, and git tags (PR: #229, @chenxiaolong)
- * The goal is to switch to stronger cryptography and rely on a simpler tool that everybody already has installed (including on Windows). For folks who were previously verifying signatures using GPG, please see the updated documentation for how to verify signatures with SSH.
- * For folks who want to verify that this change is legitimate, see commit 0bc3935fe2a1b6e3d56049503db521877501edc1. That commit, which introduced this change, was signed using the original GPG key.
- * The APK signing key remains unchanged.
-
-### Version 1.30
-
-* Update Slovak translations (PR: #217, @pvagner)
-* Update Polish translations (PR: #219, @Twoomatch)
-* Improve English description of `initially paused` preference (PR: #220, @Twoomatch)
-* Update Spanish translations (PR: #222, @nmayorga092)
-
-Magisk module updater changes:
-
-* Show changelog for the correct version, excluding unreleased changes (PR: #223, @chenxiaolong)
-
-Documentation changes:
-
-* README.md: Fix typos (PR: #221, @Twoomatch)
-
-### Version 1.29
-
-* Add a new option for starting the recording in the paused state (Issue: #198, PR: #211, @chenxiaolong)
- * If enabled, this allows the user to choose whether a call is recorded. If a recording starts in the paused state and is never resumed, then the empty output file is not saved.
-
-Documentation changes:
-
-* README.md: Document hidden/advanced features (Issue: #212, PR: #213, @chenxiaolong)
-
-### Version 1.28
-
-* Inform the user that the device/firmware might not support call recording if an error origates from Android's internal components (PR: #206, @chenxiaolong)
-* Fix crash if any filename template value (eg. caller/contact name) contains \ or $ (Issue: #207, PR: #209, @chenxiaolong)
-* Add support for pausing/resuming the recording (Issue: #198, PR: #210, @chenxiaolong)
- * The button is in the `Call recording in progress` notification
-
-### Version 1.27
-
-* Update Polish translations (PR: #192, @Twoomatch)
-* Update Spanish translations (PR: #201, @nmayorga092)
-* Fix silent crash causing recording to not happen when debug mode is enabled (Issue: #195, PR: #203, @chenxiaolong)
- * The bug was introduced in version 1.26
-* Add support for changing the filename timestamp format (Issue: #204, PR: #205, @chenxiaolong)
- * Similar to the existing output filename options, this can only be done via the `bcr.properties` config file
-
-Non-user-facing changes:
-
-* Update Kotlin and AndroidX (PR: #196, @PatrykMis)
-* Update Build Tools (PR: #199, @PatrykMis)
-
-### Version 1.26
-
-* Update Turkish and Russian translations (PR: #188, @EleoXDA)
-* Add hidden feature to customize the output filename (PR: #189, @chenxiaolong)
- * To avoid complicating BCR's code, there is no UI option for this
- * To customize the output filenames, copy [the default template](./app/src/main/res/raw/filename_template.properties) to `bcr.properties` in the output directory and edit the file
-
-### Version 1.25
-
-* Add SIM slot ID to the filename if there are multiple active SIMs (Issue: #177, PR: #178, @chenxiaolong)
-* Fix share action in the recording complete notification always referencing an old recording (PR: #181, @chenxiaolong)
-* Add a new Delete action alongside Open and Share in the notifications (Issue: #179, PR: #182, @chenxiaolong)
-* Allow changing output settings when call recording is disabled (PR: #183, @chenxiaolong)
-
-Documentation changes:
-
-* README.md: Explain what every permission is used for (PR: #180, @chenxiaolong)
-
-Non-user-facing changes:
-
-* Update gradle wrapper to 7.6.0 (PR: #174, @PatrykMis)
-
-### Version 1.24
-
-* Notification improvements (PR: #169, @chenxiaolong)
- * A notification is now shown when a recording completes, with options for opening or sharing the recording in a 3rd party app.
- * **NOTE: Manual action required.** For opening/sharing recordings to work, reset the output directory to the default and then select the output directory again. This is required because BCR previously only requested write access to the output directory, but not read access.
- * These new notifications can be disabled in Android's settings by turning off the `Success alerts` notification channel.
- * The file path in error notifications is now human readable instead of a URL-encoded `content://...`.
-* BCR will explicitly vibrate if vibration is enabled for its notification channels (PR: #167, #171, @quyenvsp, @chenxiaolong)
- * This is needed because Android will not respect the notification vibration option during a phone call.
-
-Non-user-facing changes:
-
-* Updated all dependencies (PR: #160, @PatrykMis)
-* Fixed Gradle non-laziness, causing the execution of specific tasks to be slower (PR: #168, @chenxiaolong)
-
-### Version 1.23
-
-* Update all dependencies and fix build system lint issues (PR: #155, @PatrykMis)
-* Add Slovak translation (PR: #161, @pvagner)
-
-### Version 1.22
-
-* (Direct installs only) Add `/system/addon.d/` script to persist installation across OS updates (Issue: #142, PR: #144, @chenxiaolong)
- * Only applies to LineageOS-based firmware
-* Improve logging in debug mode (Issue: #143, PR: #145, #147, #148, @chenxiaolong)
- * Run logcat interactively for the duration of the call to ensure no lost log messages due to logcat overflow
- * Include BCR version number in the logs
-* Improve output file writing reliability (Issue: #143, PR: #146, #149, #150, @chenxiaolong)
-* Improve call disconnection detection on buggy firmware (Issue: #143, PR: #151, @chenxiaolong)
- * Works around Samsung OneUI's telephony framework bug where Android does not notify apps (including their own) when a call disconnects
-* Use non-blocking reads from call audio stream (Issue: #143, PR: #152, @chenxiaolong)
- * Fixes recordings not stopping until another call becomes active on Samsung OneUI because `AudioRecord.read()` blocks forever as soon as a call disconnects
-
-### Version 1.21
-
-* (Direct installs only) Explicitly remount system as writable and ignore `ENOENT` errors during cleanup (Issue: #108, #138, PR: #139, @chenxiaolong)
-* Updated all dependencies (PR: #140, @chenxiaolong)
-
-### Version 1.20
-
-* Update dependencies (PR: #121, #132, @PatrykMis)
-* Perform a direct install if `/system/bin/recovery` exists in the environment (Issue: #131, PR: #133, @chenxiaolong)
- * Previously, only `/sbin/recovery` was used to detect if booted into recovery
-
-### Version 1.19
-
-* Add support for flashing via recovery (Issue: #128, PR: #130, @chenxiaolong)
- * This is for unrooted (non-Magisk) installs only. BCR will be installed to the system partition directly when flashed via recovery.
-
-### Version 1.18
-
-* Update gradle wrapper to 7.5.1 (PR: #116, @PatrykMis)
-* Fix plurals in Russian translations (PR: #117, @EleoXDA)
-* Add French translation (PR: #120, @NSO73)
-
-### Version 1.17
-
-* Update dependencies and gradle wrapper (PR: #112, @PatrykMis)
-* Update Polish translations (PR: #112, @PatrykMis)
-* Fix silent crash when receiving a call from a private number (Issue: #111, PR: #114, @chenxiaolong)
-
-### Version 1.16
-
-* Update Turkish translations (PR: #106, @EleoXDA)
-* Update Russian translations (PR: #107, @EleoXDA)
-
-### Version 1.15
-
-* Update Spanish translations (PR: #92, @nmayorga092)
-* Update Turkish translations (PR: #97, @EleoXDA)
-
-### Version 1.14
-
-* Add support for a basic file retention policy (Issue: #25 #81 #88, PR: #90, @chenxiaolong)
-
-Non-user-facing changes:
-
-* Improve type-safety when loading and saving preferences (PR: #91, @chenxiaolong)
-
-### Version 1.13
-
-* Add Polish translations (PR: #76, @uvzen)
-* Target stable API 33 (Tiramisu) (PR: #82, @chenxiaolong)
-* Add optional contacts permission to initial permissions prompt (Issue: #78 #80, PR: #84, @chenxiaolong)
- * If allowed, contact names are added to the output filenames.
- * This feature was implemented in version 1.5, but required the user to manually enable from the system settings.
-
-Non-user-facing changes:
-
-* Update Android gradle plugin to 7.2.1 and Kotlin to 1.7.0 (PR: #83, @chenxiaolong)
-
-### Version 1.12
-
-* Fix potential crash when showing user-friendly output directory path (PR: #74, @chenxiaolong)
- * Fixes regression in version 1.11
-
-### Version 1.11
-
-* Fix persistent notification icon being too small (PR: #67, @chenxiaolong)
-* Increase internal buffer sizes to reduce chance of encoding slowdowns causing audible artifacts (Issue: #39 #54, PR: #69 #73, @chenxiaolong)
- * The native sample rate option had to be removed for this change
-* Show user-friendly path instead of a raw URI for the output directory (PR: #71, @chenxiaolong)
-* Work around SAF slowness by recording to the default directory and then moving to the user directory after recording is completed (Issue: #39 #54, PR: #72, @chenxiaolong)
-
-Non-user-facing changes:
-
-* Change Container abstract class to an interface (PR: #68, @chenxiaolong)
-* Update all gradle dependencies (PR: #70, @chenxiaolong)
-
-### Version 1.10
-
-* Update Spanish translations (PR: #64, @nmayorga092)
-* Add hidden debug mode, which saves logs for each recording (long press version number to enable) (PR: #65, @chenxiaolong)
-* Set recording thread priority to THREAD_PRIORITY_URGENT_AUDIO (Issue: #39 #54, PR: #66, @chenxiaolong)
-
-### Version 1.9
-
-* Improve buffering to reduce chance of audio drops (Issue: #39 #54, PR: #61, @chenxiaolong)
-
-### Version 1.8
-
-* Update Turkish translations (PR: #58, @fnldstntn)
-* Fix overlapping audio and other audible artifacts when using an encoded format (OPUS, AAC, or FLAC) (Issue: #39 #54, PR: #59, @chenxiaolong)
-
-### Version 1.7
-
-* Change output format button group to material chips to prevent text from being cut off with narrower screen widths (Issue: #52, PR: #55, @chenxiaolong)
-* Add support for configuring the capture sample rate (PR: #56, @chenxiaolong)
-* Send notification if an error occurs during call recording (PR: #57, @chenxiaolong)
-
-### Version 1.6
-
-* Enable minification (without obfuscation) to shrink the download size by ~64% (PR: #45, @chenxiaolong)
-* Update Turkish translations (PR: #46, @fnldstntn)
-* Add support for WAV/PCM output for troubleshooting (bypasses encoding/compression pipeline) (PR: #48, @chenxiaolong)
-
-Non-user-facing changes:
-
-* Improve output format parameter abstraction (PR: #49, @chenxiaolong)
-* Use view binding instead of findViewById where possible (PR: #50, @chenxiaolong)
-
-### Version 1.5
-
-* Optionally add contact name to output filename if Contacts permission is granted (Android 11+) (Issue: #28, PR: #42, @chenxiaolong)
-* Add Spanish translation (PR: #41, @nmayorga092)
-* Redact sensitive information from logcat logs (PR: #43, @chenxiaolong)
-
-### Version 1.4
-
-* Add support for configurable output formats: OGG/Opus (Android 10+), M4A/AAC, FLAC (Issue: #21, PR: #29, #32, #34, #35, #38, @chenxiaolong)
-* README.md: Remove mention of cloud storage. Android's Storage Access Framework does not support cloud storage when opening folders (Issue: #30, PR: #31, @chenxiaolong)
-* Add full changelog text for updates from Magisk Manager (PR: #36, @chenxiaolong)
-
-Non-user-facing changes:
-
-* Fix minor compiler warnings (PR: #37, @chenxiaolong)
-
-### Version 1.3
-
-* Write audio duration to FLAC metadata after recording is complete (Issue: #19, PR: #20, @chenxiaolong)
-* Add Turkish translations (Issue: #18, PR: #22, @fnldstntn)
-
-Non-user-facing changes:
-
-* Don't add irrelevant update metadata to release zips (PR: #23, @chenxiaolong)
-* Fix serialization exception when running the `updateJson` gradle tasks (PR: #24, @chenxiaolong)
-
-### Version 1.2
-
-* Fix typo and improve wording of battery optimization preference (PR: #4, @EleoXDA)
-* Add Russian translations (PR: #7, @marat2509)
-* Add support for API 28 (Android 9) (Issue: #6, PR: #10, @chenxiaolong)
-* Add incoming/outgoing tag to filenames (Issue: #3, PR: #11, @chenxiaolong)
-* Add caller ID to filenames for incoming calls (Android 10+ only) (Issue: #3, PR: #13, @chenxiaolong)
-* Fix filename timestamps to match the call log exactly (Issue: #3, PR: #12, @chenxiaolong)
-* The about link in the app now links to the exact commit the version was built from (PR: #15, @chenxiaolong)
-* Add support for Magisk's built-in module updater (PR: #16, @chenxiaolong)
-
-Non-user-facing changes:
-
-* Update gradle and Android gradle plugin dependencies (PR: #9, @chenxiaolong)
-* Add git commit to version number for debug builds (PR: #14, @chenxiaolong)
-* Ensure custom gradle tasks (`moduleProp`, `permissionsXml`, `zip`, and `updateJson`) rebuild when input variables (eg. git commit) change (PR: #17, @chenxiaolong)
-
-### Version 1.1
-
-* Target Android SDK 32. BCR was previously targeting the Tiramisu (33) preview SDK, which made it not installable on stable Android versions. (Issue: #1, PR: #2, @chenxiaolong)
-
### Version 1.0
* Initial release
diff --git a/README.md b/README.md
index 956677ca9..4f92bdd4a 100644
--- a/README.md
+++ b/README.md
@@ -1,200 +1,56 @@
-# Basic Call Recorder
+# Basic Audio Recorder
-
+
-
-
+BAR is a simple Android audio recording app forked from [BCR](https://github.com/chenxiaolong/BCR) with an addition of [this pull request from the original author](https://github.com/chenxiaolong/BCR/pull/165). This fork has stripped out functionality / code related to call recording and uses the same codebase as BCR.
-BCR is a simple Android call recording app for rooted devices or devices running custom firmware. Once enabled, it stays out of the way and automatically records incoming and outgoing calls in the background.
-
-
+I've decided to fork because BCR has a robust audio recording/encoding pipeline that supports multiple output formats and accounts for many edge cases and failure conditions that other apps may ignore. It records from Android's MIC audio source (todo: source selector) and passes the audio through the same encoding pipeline as with call recording. The output files are saved with a _mic suffix in the output directory.
### Features
-* Supports Android 9 through 13
+* Supports Android 13 through 16
* Supports output in various formats:
- * OGG/Opus - Lossy, smallest files, default on Android 10+
- * M4A/AAC - Lossy, smaller files, default on Android 9
+ * OGG/Opus - Lossy, smallest files, default
+ * M4A/AAC - Lossy, smaller files
* FLAC - Lossless, larger files
* WAV/PCM - Lossless, largest files, least CPU usage
* Supports Android's Storage Access Framework (can record to SD cards, USB devices, etc.)
* Quick settings toggle
* Material You dynamic theming
-* No persistent notification unless a recording is in progress
* No network access permission
* No third party dependencies
-* Works with call screening on Pixel devices (records the caller, but not the automated system)
### Non-features
-As the name alludes, BCR intends to be a basic as possible. The project will have succeeded at its goal if the only updates it ever needs are for compatibility with new Android versions. Thus, many potentially useful features will never be implemented, such as:
+As the name alludes, BAR intends to be a basic as possible. The project will have succeeded at its goal if the only updates it ever needs are for compatibility with new Android versions. Thus, many potentially useful features will never be implemented, such as:
-* Support for old Android versions (support is dropped as soon as maintenance becomes cumbersome)
-* Workarounds for [OEM-specific battery optimization and app killing behavior](https://dontkillmyapp.com/)
-* Workarounds for devices that don't support the [`VOICE_CALL` audio source](https://developer.android.com/reference/android/media/MediaRecorder.AudioSource#VOICE_CALL) (eg. using microphone + speakerphone)
+* Changing the filename format
+* Support for old (unsupported) Android versions (support is dropped as soon as maintenance becomes cumbersome)
* Support for direct boot mode (the state before the device is initially unlocked after reboot)
-* Support for stock, unrooted firmware
### Usage
-1. Download the latest version from the [releases page](https://github.com/chenxiaolong/BCR/releases). To verify the digital signature, see the [verifying digital signatures](#verifying-digital-signatures) section.
-
-2. Install BCR as a system app.
-
- * **For devices rooted with Magisk**, simply flash the zip as a Magisk module from within the Magisk app.
- * **For OnePlus and Realme devices running the stock firmware (or custom firmware based on the stock firmware)**, also extract the `.apk` from the zip and install it manually before rebooting. This is necessary to work around a bug in the firmware where the app data directory does not get created, causing BCR to open up to a blank screen.
-
- * **For unrooted custom firmware**, flash the zip while booted into recovery.
- * **NOTE**: If the custom firmware's `system` partition is formatted with `erofs`, then the filesystem is read-only and it is not possible to use this method.
- * Manually extracting the files from the `system/` folder in the zip will also work as long as the files have `644` permissions and the `u:object_r:system_file:s0` SELinux label.
-
-3. Reboot and open BCR.
-
-4. Enable call recording and pick an output directory. If no output directory is selected or if the output directory is no longer accessible, then recordings will be saved to `/sdcard/Android/data/com.chiller3.bcr/files`.
-
- When enabling call recording the first time, BCR will prompt for microphone, notification (Android 13+), contacts, and phone permissions. Only microphone and notification permissions are required basic call recording functionality. If additional permissions are granted, more information is added to the output filename. For example, the contacts permission will cause the contact name to be added to the filename and the phone permission will cause the SIM slot (if multiple SIMs are active) to be added to the filename.
-
- See the [permissions section](#permissions) below for more details about the permissions.
-
-5. To install future updates, there are a couple methods:
-
- * If installed via Magisk, the module can be updated right from Magisk Manager's modules tab. Flashing the new version in Magisk manually also works just as well.
- * The `.apk` can also be extracted from the zip and be directly installed. With this method, the old version exists as a system app and the new version exists as a user-installed update to the system app. This method is more convenient if BCR is baked into the Android firmware image.
-
-### Permissions
-
-* `CAPTURE_AUDIO_OUTPUT` (**automatically granted by system app permissions**)
- * Needed to capture the call audio stream.
-* `CONTROL_INCALL_EXPERIENCE` (**automatically granted by system app permissions**)
- * Needed to monitor the phone call state for starting and stopping the recording and gathering call information for the output filename.
-* `RECORD_AUDIO` (**must be granted by the user**)
- * Needed to capture the call audio stream.
-* `FOREGROUND_SERVICE` (**automatically granted at install time**)
- * Needed to run the call recording service.
-* `POST_NOTIFICATIONS` (**must be granted by the user on Android 13+**)
- * Needed to show notifications.
- * A notification is required for running the call recording service in foreground mode or else Android will not allow access to the call audio stream.
-* `READ_CONTACTS` (**optional**)
- * If allowed, the contact name is added to the output filename.
-* `READ_PHONE_STATE` (**optional**)
- * If allowed, the SIM slot for devices with multiple active SIMs is added to the output filename.
-* `REQUEST_IGNORE_BATTERY_OPTIMIZATIONS` (**optional**)
- * If allowed, request Android to disable battery optimizations (app killing) for BCR.
- * This is usually not needed. The way BCR hooks into the telephony system makes it unlikely to be killed.
- * OEM Android builds that stray further from AOSP may ignore this.
-* `VIBRATE` (**automatically granted at install time**)
- * If vibration is enabled for BCR's notifications in Android's settings, BCR will perform the vibration. Android itself does not respect the vibration option when a phone call is active.
-
-Note that `INTERNET` is _not_ in the list. BCR does not and will never access the network. BCR will never communicate with other apps either, except if the user explicitly taps on the `Open` or `Share` buttons in the notification shown when a recording completes. In that scenario, the target app is granted access to that single recording only.
-
-### Advanced features
-
-This section describes BCR's advanced features that are hidden or only accessible via a config file.
-
-#### Debug mode
-
-BCR has a hidden debug mode that can be enabled or disabled by long pressing the version number.
-
-When debug mode is enabled, BCR will write a log file to the output directory after a call recording completes. It is named the same way as the audio file. The log file contains the same messages as what `adb logcat` would show, except messages not relevant to BCR are filtered out (BCR does not have permission to access those messages anyway).
-
-Within the log file, BCR aims to never log any sensitive information. Information about the current call, like the phone number, are replaced with placeholders instead, like ``. However, other information can't be easily redacted this way will be truncated instead. For example, when the file retention feature cleans up old files, filenames like `20230101_010203.456+0000_out_1234567890_John_Doe.oga` are logged as `20<...>ga`.
-
-When reporting bugs, please include the log file as it is extremely helpful for identifying what might be wrong. (But please double check the log file to ensure there's no sensitive information!)
-
-#### Customizing the output filename
-
-By default, BCR uses a filename template that includes the call timestamp, call direction, SIM slot, phone number, caller ID, and contact name. This can be customized, but only by editing a config file. To do so, the easiest way is to copy [the default config](./app/src/main/res/raw/filename_template.properties) to `bcr.properties` in the output directory and then edit it to your liking. Details about the available fields are documented in the default config file.
-
-For example, to customize the filename template to `__`, use the following config:
-
-```properties
-filename.0.text = ${date:yyyyMMdd_HHmmss}
-
-filename.1.text = ${phone_number}
-filename.1.prefix = _
-
-filename.2.text = ${caller_name}
-filename.2.prefix = _
-```
-
-The are a couple limitations to note:
-
-* The date must always be at the beginning of the filename. This is required for the file retention feature to work.
-* If the date format is changed (eg. from the default to `yyyyMMdd_HHmmss`), then you must manually rename the old recordings to use the new date format or they may be handled incorrectly by the file retention feature. To be safe, move the old recordings to a different folder while testing (or set the file retention to `Keep all`).
-
-If the config file has any error, BCR will use the default configuration. This ensures that recordings won't fail if the configuration is incorrect. To troubleshoot issues with the filename template, [enable debug mode](#debug-mode), and make a call. Then, search the log file for `FilenameTemplate`.
-
-### How it works
+1. Download the latest version from the [todo: releases page](https://github.com/PatrykMis/BAR/releases). To verify the digital signature, see the [verifying digital signatures](#verifying-digital-signatures) section.
-BCR relies heavily on system app permissions in order to function properly. This is primarily because of two permissions:
+2. Install BAR.
-* `CONTROL_INCALL_EXPERIENCE`
+3. Open BAR.
- This permission allows Android's telephony service to bind to BCR's `InCallService` without BCR being a wearable companion app, a car UI, or the default dialer. Once bound, the service will receive callbacks for call change events (eg. incoming call in the ringing state). This method is much more reliable than using the `READ_PHONE_STATE` permission and relying on `android.intent.action.PHONE_STATE` broadcasts.
+4. Pick an output directory. If no output directory is selected or if the output directory is no longer accessible, then recordings will be saved to `/sdcard/Android/data/com.patrykmis.bar/files`.
- This method has a couple additional benefits. Due to the way that the telephony service binds to BCR's `InCallService`, the service can bring itself in and out of the foreground as needed when a call is in progress and access the audio stream without hitting Android 12+'s background microphone access limitations. It also does not require the service to be manually started from an `ACTION_BOOT_COMPLETED` broadcast receiver and thus is not affected by that broadcast's delays during initial boot.
-
-* `CAPTURE_AUDIO_OUTPUT`
-
- This permission is used to record from the `VOICE_CALL` audio stream. This stream, along with some others, like `VOICE_DOWNLINK` and `VOICE_UPLINK`, cannot be accessed without this system permission.
-
-With these two permissions, BCR can reliably detect phone calls and record from the call's audio stream. The recording process pulls PCM s16le raw audio and uses Android's built-in encoders to produce the compressed output file.
-
-### Verifying digital signatures
-
-Both the zip file and the APK contained within are digitally signed. **NOTE**: The zip file signing mechanism switched from GPG to SSH as of version 1.31. To verify signatures for old versions, see version 1.30's [`README.md`](https://github.com/chenxiaolong/BCR/blob/v1.30/README.md#verifying-digital-signatures).
-
-#### Verifying zip file signature
-
-First save the public key to a file that lists which keys should be trusted.
-
-```bash
-echo 'bcr ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDOe6/tBnO7xZhAWXRj3ApUYgn+XZ0wnQiXM8B7tPgv4' > bcr_trusted_keys
-```
-
-Then, verify the signature of the zip file using the list of trusted keys.
-
-```bash
-ssh-keygen -Y verify -f bcr_trusted_keys -I bcr -n file -s BCR--release.zip.sig < BCR--release.zip
-```
-
-If the file is successfully verified, the output will be:
-
-```
-Good "file" signature for bcr with ED25519 key SHA256:Ct0HoRyrFLrnF9W+A/BKEiJmwx7yWkgaW/JvghKrboA
-```
-
-#### Verifying apk signature
-
-First, extract the apk from the zip and then run:
-
-```
-apksigner verify --print-certs system/priv-app/com.chiller3.bcr/app-release.apk
-```
-
-Then, check that the SHA-256 digest of the APK signing certificate is:
-
-```
-d16f9b375df668c58ef4bb855eae959713d6d02e45f7f2c05ce2c27ae944f4f9
-```
+For the first time, BAR will prompt for microphone, and notification (Android 13+) permissions. They are required for BAR to be able to record in the background.
### Building from source
-BCR can be built like most other Android apps using Android Studio or the gradle command line.
+BAR can be built like most other Android apps using Android Studio or the gradle command line.
-To build the APK:
+To build the debug APK:
```bash
./gradlew assembleDebug
```
-To build the Magisk module zip (which automatically runs the `assembleDebug` task if needed):
-
-```bash
-./gradlew zipDebug
-```
-
-The output file is written to `app/build/distributions/debug/`. The APK will be signed with the default autogenerated debug key.
+The output file is written to `app/build/outputs/apk/debug/`. The APK will be signed with the default autogenerated debug key.
To create a release build with a specific signing key, set up the following environment variables:
@@ -208,18 +64,18 @@ export RELEASE_KEYSTORE_PASSPHRASE
export RELEASE_KEY_PASSPHRASE
```
-and then build the release zip:
+and then build the release APK:
```bash
-./gradlew zipRelease
+./gradlew assembleRelease
```
### Contributing
Bug fix and translation pull requests are welcome and much appreciated!
-If you are interested in implementing a new feature and would like to see it included in BCR, please open an issue to discuss it first. I intend for BCR to be as simple and low-maintenance as possible, so I am not too inclined to add any new features, but I could be convinced otherwise.
+If you are interested in implementing a new feature and would like to see it included in BAR, please open an issue to discuss it first. I intend for BAR to be as simple and low-maintenance as possible, so I am not too inclined to add any new features, but I could be convinced otherwise.
### License
-BCR is licensed under GPLv3. Please see [`LICENSE`](./LICENSE) for the full license text.
+BAR is licensed under GPLv3. Please see [`LICENSE`](./LICENSE) for the full license text.
diff --git a/RELEASE.md b/RELEASE.md
index 6dac8d524..372e30dca 100644
--- a/RELEASE.md
+++ b/RELEASE.md
@@ -2,6 +2,4 @@ The changelog can be found at: [`CHANGELOG.md`](./CHANGELOG.md).
---
-See [`README.md`](./README.md) for information on how to install and use BCR.
-
-The downloads are digitally signed. Please consider [verifying the digital signatures](./README.md#verifying-digital-signatures) because BCR is installed as a privileged system app.
+See [`README.md`](./README.md) for information on how to install and use BAR.
diff --git a/app/.gitignore b/app/.gitignore
index 42afabfd2..3543521e9 100644
--- a/app/.gitignore
+++ b/app/.gitignore
@@ -1 +1 @@
-/build
\ No newline at end of file
+/build
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index c4521e516..4b27bd997 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -1,117 +1,47 @@
-import org.eclipse.jgit.api.ArchiveCommand
-import org.eclipse.jgit.api.Git
-import org.eclipse.jgit.archive.TarFormat
-import org.eclipse.jgit.lib.ObjectId
-import org.jetbrains.kotlin.backend.common.pop
-import org.json.JSONObject
+import java.io.FileInputStream
+import java.util.Properties
plugins {
- id("com.android.application")
- id("org.jetbrains.kotlin.android")
+ alias(libs.plugins.android.application)
}
-buildscript {
- dependencies {
- classpath("org.eclipse.jgit:org.eclipse.jgit:6.5.0.202303070854-r")
- classpath("org.eclipse.jgit:org.eclipse.jgit.archive:6.5.0.202303070854-r")
- classpath("org.json:json:20230227")
- }
+val keystorePropertiesFile = rootProject.file("keystore.properties")
+val useKeystoreProperties = keystorePropertiesFile.canRead()
+val keystoreProperties = Properties()
+if (useKeystoreProperties) {
+ keystoreProperties.load(FileInputStream(keystorePropertiesFile))
}
-typealias VersionTriple = Triple
-
-fun describeVersion(git: Git): VersionTriple {
- // jgit doesn't provide a nice way to get strongly-typed objects from its `describe` command
- val describeStr = git.describe().setLong(true).call()
-
- return if (describeStr != null) {
- val pieces = describeStr.split('-').toMutableList()
- val commit = git.repository.resolve(pieces.pop().substring(1))
- val count = pieces.pop().toInt()
- val tag = pieces.joinToString("-")
-
- Triple(tag, count, commit)
- } else {
- val log = git.log().call().iterator()
- val head = log.next()
- var count = 1
-
- while (log.hasNext()) {
- log.next()
- ++count
- }
-
- Triple(null, count, head.id)
- }
+kotlin {
+ jvmToolchain(17)
}
-fun getVersionCode(triple: VersionTriple): Int {
- val tag = triple.first
- val (major, minor) = if (tag != null) {
- if (!tag.startsWith('v')) {
- throw IllegalArgumentException("Tag does not begin with 'v': $tag")
- }
-
- val pieces = tag.substring(1).split('.')
- if (pieces.size != 2) {
- throw IllegalArgumentException("Tag is not in the form 'v.': $tag")
+android {
+ if (useKeystoreProperties) {
+ signingConfigs {
+ create("release") {
+ keyAlias = keystoreProperties["keyAlias"] as String
+ keyPassword = keystoreProperties["keyPassword"] as String
+ storeFile = file(keystoreProperties["storeFile"]!!)
+ storePassword = keystoreProperties["storePassword"] as String
+ enableV2Signing = false
+ enableV3Signing = true
+ enableV4Signing = true
+ }
}
-
- Pair(pieces[0].toInt(), pieces[1].toInt())
- } else {
- Pair(0, 0)
}
- // 8 bits for major version, 8 bits for minor version, and 8 bits for git commit count
- assert(major in 0 until 1.shl(8))
- assert(minor in 0 until 1.shl(8))
- assert(triple.second in 0 until 1.shl(8))
-
- return major.shl(16) or minor.shl(8) or triple.second
-}
-
-fun getVersionName(git: Git, triple: VersionTriple): String {
- val tag = triple.first?.replace(Regex("^v"), "") ?: "NONE"
+ namespace = "com.patrykmis.bar"
- return buildString {
- append(tag)
-
- if (triple.second > 0) {
- append(".r")
- append(triple.second)
-
- append(".g")
- git.repository.newObjectReader().use {
- append(it.abbreviate(triple.third).name())
- }
+ compileSdk {
+ version = release(36) {
+ minorApiLevel = 1
}
}
-}
+ buildToolsVersion = "36.1.0"
-val git = Git.open(File(rootDir, ".git"))!!
-val gitVersionTriple = describeVersion(git)
-val gitVersionCode = getVersionCode(gitVersionTriple)
-val gitVersionName = getVersionName(git, gitVersionTriple)
-
-val projectUrl = "https://github.com/chenxiaolong/BCR"
-val releaseMetadataBranch = "master"
-
-val extraDir = File(buildDir, "extra")
-val archiveDir = File(extraDir, "archive")
-
-android {
- namespace = "com.chiller3.bcr"
-
- compileSdk = 33
- buildToolsVersion = "33.0.2"
-
- defaultConfig {
- applicationId = "com.chiller3.bcr"
- minSdk = 28
- targetSdk = 33
- versionCode = gitVersionCode
- versionName = gitVersionName
- resourceConfigurations.addAll(listOf(
+ androidResources {
+ localeFilters += listOf(
"en",
"es",
"fr",
@@ -121,33 +51,23 @@ android {
"sk",
"tr",
"zh-rCN"
- ))
-
- testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
-
- buildConfigField("String", "PROJECT_URL_AT_COMMIT",
- "\"${projectUrl}/tree/${gitVersionTriple.third.name}\"")
+ )
+ }
- buildConfigField("String", "PROVIDER_AUTHORITY",
- "APPLICATION_ID + \".provider\"")
+ defaultConfig {
+ applicationId = "com.patrykmis.bar"
+ minSdk = 33
+ targetSdk = 36
+ versionCode = 1
+ versionName = versionCode.toString()
+
+ buildConfigField(
+ "String", "PROVIDER_AUTHORITY",
+ "APPLICATION_ID + \".provider\""
+ )
resValue("string", "provider_authority", "$applicationId.provider")
}
- sourceSets {
- getByName("main") {
- assets {
- srcDir(archiveDir)
- }
- }
- }
- signingConfigs {
- create("release") {
- val keystore = System.getenv("RELEASE_KEYSTORE")
- storeFile = if (keystore != null) { File(keystore) } else { null }
- storePassword = System.getenv("RELEASE_KEYSTORE_PASSPHRASE")
- keyAlias = System.getenv("RELEASE_KEY_ALIAS")
- keyPassword = System.getenv("RELEASE_KEY_PASSPHRASE")
- }
- }
+
buildTypes {
getByName("debug") {
buildConfigField("boolean", "FORCE_DEBUG_MODE", "true")
@@ -158,7 +78,10 @@ android {
isMinifyEnabled = true
isShrinkResources = true
- proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
signingConfig = signingConfigs.getByName("debug")
}
@@ -168,271 +91,44 @@ android {
isMinifyEnabled = true
isShrinkResources = true
- proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
- signingConfig = signingConfigs.getByName("release")
+ if (useKeystoreProperties) {
+ signingConfig = signingConfigs.getByName("release")
+ }
}
}
- compileOptions {
- sourceCompatibility(JavaVersion.VERSION_11)
- targetCompatibility(JavaVersion.VERSION_11)
- }
- kotlinOptions {
- jvmTarget = "11"
- }
buildFeatures {
buildConfig = true
+ resValues = true
viewBinding = true
}
-}
-
-dependencies {
- implementation("androidx.activity:activity-ktx:1.7.2")
- implementation("androidx.appcompat:appcompat:1.6.1")
- implementation("androidx.core:core-ktx:1.10.1")
- implementation("androidx.documentfile:documentfile:1.0.1")
- implementation("androidx.fragment:fragment-ktx:1.5.7")
- implementation("androidx.preference:preference-ktx:1.2.0")
- implementation("com.google.android.material:material:1.9.0")
- testImplementation("junit:junit:4.13.2")
- androidTestImplementation("androidx.test.ext:junit:1.1.5")
- androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
-}
-
-val archive = tasks.register("archive") {
- inputs.property("gitVersionTriple.third", gitVersionTriple.third)
-
- val outputFile = File(archiveDir, "archive.tar")
- outputs.file(outputFile)
-
- doLast {
- val format = "tar_${Thread.currentThread().id}"
-
- ArchiveCommand.registerFormat(format, TarFormat())
- try {
- outputFile.outputStream().use {
- git.archive()
- .setTree(git.repository.resolve(gitVersionTriple.third.name))
- .setFormat(format)
- .setOutputStream(it)
- .call()
- }
- } finally {
- ArchiveCommand.unregisterFormat(format)
- }
- }
-}
-
-android.applicationVariants.all {
- val variant = this
- val capitalized = variant.name.capitalize()
- val variantDir = File(extraDir, variant.name)
-
- variant.preBuildProvider.configure {
- dependsOn(archive)
- }
-
- val moduleProp = tasks.register("moduleProp${capitalized}") {
- inputs.property("projectUrl", projectUrl)
- inputs.property("releaseMetadataBranch", releaseMetadataBranch)
- inputs.property("variant.applicationId", variant.applicationId)
- inputs.property("variant.name", variant.name)
- inputs.property("variant.versionCode", variant.versionCode)
- inputs.property("variant.versionName", variant.versionName)
-
- val outputFile = File(variantDir, "module.prop")
- outputs.file(outputFile)
-
- doLast {
- val props = LinkedHashMap()
- props["id"] = variant.applicationId
- props["name"] = "BCR"
- props["version"] = "v${variant.versionName}"
- props["versionCode"] = variant.versionCode.toString()
- props["author"] = "chenxiaolong"
- props["description"] = "Basic Call Recorder"
-
- if (variant.name == "release") {
- props["updateJson"] = "${projectUrl}/raw/${releaseMetadataBranch}/app/magisk/updates/${variant.name}/info.json"
- }
-
- outputFile.writeText(props.map { "${it.key}=${it.value}" }.joinToString("\n"))
- }
- }
- val permissionsXml = tasks.register("permissionsXml${capitalized}") {
- inputs.property("variant.applicationId", variant.applicationId)
-
- val outputFile = File(variantDir, "privapp-permissions-${variant.applicationId}.xml")
- outputs.file(outputFile)
-
- doLast {
- outputFile.writeText("""
-
-
-
-
-
-
-
- """.trimIndent())
- }
+ dependenciesInfo {
+ includeInApk = false
+ includeInBundle = false
}
-
- val addonD = tasks.register("addonD${capitalized}") {
- inputs.property("variant.applicationId", variant.applicationId)
-
- // To get output apk filename
- dependsOn.add(variant.assembleProvider)
-
- val outputFile = File(variantDir, "51-${variant.applicationId}.sh")
- outputs.file(outputFile)
-
- val backupFiles = variant.outputs.map {
- "priv-app/${variant.applicationId}/${it.outputFile.name}"
- } + listOf(
- "etc/permissions/privapp-permissions-${variant.applicationId}.xml"
+ packaging {
+ resources.excludes.addAll(
+ listOf(
+ "DebugProbesKt.bin",
+ "META-INF/**.version",
+ "kotlin-tooling-metadata.json",
+ "kotlin/**.kotlin_builtins"
+ )
)
-
- doLast {
- outputFile.writeText("""
- #!/sbin/sh
- # ADDOND_VERSION=2
-
- . /tmp/backuptool.functions
-
- files="${backupFiles.joinToString(" ")}"
-
- case "${'$'}{1}" in
- backup|restore)
- for f in ${'$'}{files}; do
- "${'$'}{1}_file" "${'$'}{S}/${'$'}{f}"
- done
- ;;
- esac
- """.trimIndent())
- }
- }
-
- tasks.register("zip${capitalized}") {
- inputs.property("variant.applicationId", variant.applicationId)
- inputs.property("variant.name", variant.name)
- inputs.property("variant.versionName", variant.versionName)
-
- archiveFileName.set("BCR-${variant.versionName}-${variant.name}.zip")
- // Force instantiation of old value or else this will cause infinite recursion
- destinationDirectory.set(destinationDirectory.dir(variant.name).get())
-
- // Make the zip byte-for-byte reproducible (note that the APK is still not reproducible)
- isPreserveFileTimestamps = false
- isReproducibleFileOrder = true
-
- dependsOn.add(variant.assembleProvider)
-
- from(moduleProp.map { it.outputs })
- from(addonD.map { it.outputs }) {
- fileMode = 0b111_101_101 // 0o755; kotlin doesn't support octal literals
- into("system/addon.d")
- }
- from(permissionsXml.map { it.outputs }) {
- into("system/etc/permissions")
- }
- from(variant.outputs.map { it.outputFile }) {
- into("system/priv-app/${variant.applicationId}")
- }
-
- val magiskDir = File(projectDir, "magisk")
-
- for (script in arrayOf("update-binary", "updater-script")) {
- from(File(magiskDir, script)) {
- into("META-INF/com/google/android")
- }
- }
-
- from(File(magiskDir, "customize.sh"))
-
- from(File(rootDir, "LICENSE"))
- from(File(rootDir, "README.md"))
}
-
- tasks.register("updateJson${capitalized}") {
- inputs.property("gitVersionTriple.first", gitVersionTriple.first)
- inputs.property("projectUrl", projectUrl)
- inputs.property("variant.name", variant.name)
- inputs.property("variant.versionCode", variant.versionCode)
- inputs.property("variant.versionName", variant.versionName)
-
- val magiskDir = File(projectDir, "magisk")
- val updatesDir = File(magiskDir, "updates")
- val variantUpdateDir = File(updatesDir, variant.name)
- val jsonFile = File(variantUpdateDir, "info.json")
-
- outputs.file(jsonFile)
-
- doLast {
- if (gitVersionTriple.second != 0) {
- throw IllegalStateException("The release tag must be checked out")
- }
-
- val root = JSONObject()
- root.put("version", variant.versionName)
- root.put("versionCode", variant.versionCode)
- root.put("zipUrl", "${projectUrl}/releases/download/${gitVersionTriple.first}/BCR-${variant.versionName}-release.zip")
- root.put("changelog", "${projectUrl}/raw/${gitVersionTriple.first}/app/magisk/updates/${variant.name}/changelog.txt")
-
- jsonFile.writer().use {
- root.write(it, 4, 0)
- }
- }
- }
-}
-
-fun updateChangelog(version: String?, replaceFirst: Boolean) {
- val file = File(rootDir, "CHANGELOG.md")
- val expected = if (version != null) { "### Version $version" } else { "### Unreleased" }
-
- val changelog = mutableListOf().apply {
- // This preserves a trailing newline, unlike File.readLines()
- addAll(file.readText().lineSequence())
- }
-
- if (changelog.firstOrNull() != expected) {
- if (replaceFirst) {
- changelog[0] = expected
- } else {
- changelog.addAll(0, listOf(expected, ""))
- }
- }
-
- file.writeText(changelog.joinToString("\n"))
-}
-
-fun updateMagiskChangelog(gitRef: String) {
- File(File(File(File(projectDir, "magisk"), "updates"), "release"), "changelog.txt")
- .writeText("The changelog can be found at: [`CHANGELOG.md`]($projectUrl/blob/$gitRef/CHANGELOG.md).\n")
}
-tasks.register("changelogPreRelease") {
- doLast {
- val version = project.property("releaseVersion")
-
- updateChangelog(version.toString(), true)
- updateMagiskChangelog("v$version")
- }
-}
-
-tasks.register("changelogPostRelease") {
- doLast {
- updateChangelog(null, false)
- updateMagiskChangelog(releaseMetadataBranch)
- }
-}
-
-tasks.register("preRelease") {
- dependsOn("changelogPreRelease")
-}
-
-tasks.register("postRelease") {
- dependsOn("updateJsonRelease")
- dependsOn("changelogPostRelease")
+dependencies {
+ implementation(libs.androidx.activity)
+ implementation(libs.androidx.appcompat)
+ implementation(libs.androidx.core.ktx)
+ implementation(libs.androidx.documentfile)
+ implementation(libs.androidx.fragment.ktx)
+ implementation(libs.androidx.preference.ktx)
+ implementation(libs.material)
}
diff --git a/app/images/icon.svg b/app/images/icon.svg
index e4ef5d297..3059f923e 100644
--- a/app/images/icon.svg
+++ b/app/images/icon.svg
@@ -1,21 +1,16 @@
-