diff --git a/.forgejo/workflows/build-debug.yml b/.forgejo/workflows/build-debug.yml
index 51e802c..19a22ce 100644
--- a/.forgejo/workflows/build-debug.yml
+++ b/.forgejo/workflows/build-debug.yml
@@ -1,7 +1,7 @@
on:
push:
branches:
- - 'master'
+ - 'jmp'
jobs:
build-debug:
@@ -33,7 +33,10 @@ jobs:
uses: https://gitea.angry.im/actions/setup-android@v3
- name: Build Debug APKs
- run: ./gradlew --no-daemon assembleDebug
+ run: ./gradlew --no-daemon :app-unpriv:assembleJmpDebug
+
+ - name: Build Debug Bundle
+ run: ./gradlew --no-daemon :app-unpriv:bundleJmpDebug
- name: Copy Artifacts
run: find . -name 'app*-debug.apk' -exec cp {} . \;
diff --git a/.forgejo/workflows/release.yml b/.forgejo/workflows/release.yml
index c8a7283..6081ed4 100644
--- a/.forgejo/workflows/release.yml
+++ b/.forgejo/workflows/release.yml
@@ -1,6 +1,6 @@
on:
push:
- tags: '*'
+ tags: 'jmp-v*'
jobs:
release:
@@ -31,17 +31,23 @@ jobs:
- name: Setup Android SDK
uses: https://gitea.angry.im/actions/setup-android@v3
- - name: Build Release APK (Unprivileged / EasyEUICC only)
- run: ./gradlew --no-daemon :app-unpriv:assembleRelease
+ - name: Build Release APK
+ run: ./gradlew --no-daemon :app-unpriv:assembleJmpRelease
+
+ - name: Build Release Bundle
+ run: ./gradlew --no-daemon :app-unpriv:bundleJmpRelease
- name: Copy Debug Symbols to Release Path
- run: cp app-unpriv/build/outputs/native-debug-symbols/release/native-debug-symbols.zip app-unpriv/build/outputs/apk/release/
+ run: cp app-unpriv/build/outputs/native-debug-symbols/jmpRelease/native-debug-symbols.zip app-unpriv/build/outputs/apk/jmp/release/
+
+ - name: Copy Bundle to Release Path
+ run: cp app-unpriv/build/outputs/bundle/jmpRelease/app-unpriv-jmp-release.aab app-unpriv/build/outputs/apk/jmp/release/
- name: Create Release
uses: https://gitea.angry.im/actions/forgejo-release@v1
with:
direction: upload
- release-dir: app-unpriv/build/outputs/apk/release
+ release-dir: app-unpriv/build/outputs/apk/jmp/release
url: https://gitea.angry.im
token: ${{ secrets.FORGEJO_TOKEN }}
# Release details are expected to be edited manually
diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 0000000..7547d56
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+OpenEUICC
\ No newline at end of file
diff --git a/LAST_RELEASE_VERCODE b/LAST_RELEASE_VERCODE
new file mode 100644
index 0000000..26f42e6
--- /dev/null
+++ b/LAST_RELEASE_VERCODE
@@ -0,0 +1 @@
+294
diff --git a/README.md b/README.md
index f8019b2..3d5ed63 100644
--- a/README.md
+++ b/README.md
@@ -1,85 +1,11 @@
-
+JMP SIM Manager
+---
-A fully free and open-source Local Profile Assistant implementation for Android devices.
+This is a soft fork and branded version of [OpenEUICC](https://gitea.angry.im/PeterCxy/OpenEUICC) for the purpose of the [JMP eSIM Adapter](https://jmp.chat/esim-adapter).
-There are two variants of this project:
+The eSIM Adapter is a removable eSIM chip that enables the use of downloaded eSIM profiles on any device with a modem. New profiles can be downloaded with the JMP SIM Manager on an Android device, or through a PC/SC smart card reader plugged into the Android device. [lpac](https://github.com/estkme-group/lpac) is available for use on a Linux/Windows/macOS PC.
-- OpenEUICC: The full-fledged privileged variant.
- - Due to its privilege requirement, OpenEUICC must be placed inside `/system/priv-app` and be signed with the platform certificate.
- - The preferred way to including OpenEUICC in a system image is to [build it along with AOSP](#building-aosp).
- - __Note__: When privileged, OpenEUICC supports any eUICC chip that implements the SGP.22 standard, internal or external. However, there is __no guarantee__ that external (removable) eSIMs actually follow the standard. Please __DO NOT__ submit bug reports for non-functioning removable eSIMs. They are __NOT__ officially supported unless they also support / are supported by EasyEUICC, the unprivileged variant.
-- EasyEUICC: Unprivileged version that can run as a user app.
- - This version supports two modes of operation:
- 1. Inserted, removable eSIMs: Due to obvious security requirements, EasyEUICC is only able to access eSIM chips whose [ARF/ARA](https://source.android.com/docs/core/connect/uicc#arf) contains the hash of EasyEUICC's signing certificate.
- 2. USB CCID Card Readers: Only `T=0` readers that use the standard [USB CCID protocol](https://en.wikipedia.org/wiki/CCID_(protocol)) are supported. In this mode, EasyEUICC can access any eSIM chip loaded in the card reader regardless of their ARF/ARA, as long as they implement the [SGP.22 standard](https://www.gsma.com/solutions-and-impact/technologies/esim/wp-content/uploads/2021/07/SGP.22-v2.3.pdf).
- - Prebuilt release-mode EasyEUICC apks can be downloaded [here](https://gitea.angry.im/PeterCxy/OpenEUICC/releases)
- - For removable eSIM chip vendors: to have your chip supported by official builds of EasyEUICC when inserted, include the ARA-M hash `2A2FA878BC7C3354C2CF82935A5945A3EDAE4AFA`
-
-__This project is Free Software licensed under GNU GPL v3, WITHOUT the "or later" clause.__ Any modification and derivative work __MUST__ be released under the SAME license, which means, at the very least, that the source code __MUST__ be available upon request.
-
-__If you are releasing a modification of this app, you are kindly asked to make changes to at least the app name and package name.__
-
-Building (Gradle)
-===
-
-Make sure you have all submodules cloned and updated by running
-
-```shell
-git submodule update --init
-```
-
-A file `keystore.properties` is required in the root directory. Template:
-
-```ini
-storePassword=my-store-password
-keyPassword=my-password
-keyAlias=my-key
-unprivKeyPassword=my-unpriv-password
-unprivKeyAlias=my-unpriv-key
-storeFile=/path/to/android/keystore
-```
-
-Note that you must have a Java-compatible keystore generated first.
-
-To build the privileged OpenEUICC:
-
-```shell
-./gradlew :app:assembleRelease
-```
-
-For EasyEUICC:
-
-```shell
-./gradlew :app-unpriv:assembleRelease
-```
-
-Building (AOSP)
-===
-
-There are two ways to include OpenEUICC in your AOSP-based system image:
-
-1. Include this project and its [dependencies](https://gitea.angry.im/PeterCxy/android_prebuilts_openeuicc-deps) inside the AOSP tree.
- - If inclusion in `manifest.xml` is required, remember to set the `sync-s` option to clone submodules.
- - The module name is `OpenEUICC`. You can include it in `PRODUCT_PACKAGES`, or simply build it standalone using `mm`.
- - Compilation of this project is **only** tested against the latest AOSP release version. The app itself should be compatible with older AOSP versions, but the source may not compile against an older AOSP source tree.
-2. If compilation against AOSP source tree is not possible, consider [building with gradle](#building-gradle) and import the apk as a prebuilt.
- - No official `Android.bp` is provided for this case but it should be straightforward to write.
- - You might want to include `privapp_whitelist_im.angry.openeuicc.xml` as well.
-
-FAQs
-===
-
-- Q: Do you provide prebuilt binaries for OpenEUICC?
-- A: Debug-mode APKs are available continuously as an artifact of the [Actions](https://gitea.angry.im/PeterCxy/OpenEUICC/actions) CI used by this project. However, these debug-mode APKs are **not** intended for inclusion inside system images, nor are they supported by the developer in any sense. If you are a custom ROM developer, either include the entire OpenEUICC repository in your AOSP source tree, or generate an APK using `gradle` and import that as a prebuilt system app. Note that you might want `privapp_whitelist_im.angry.openeuicc.xml` as well.
-
-- Q: AOSP's Settings app seems to be confused by OpenEUICC (for example, disabling / enabling profiles from the Networks page do not work properly)
-- A: When your device has internal eSIM chip(s) __and__ you have inserted a removable eSIM chip, the Settings app can misbehave since it was never designed for this scenario. __Please prefer using OpenEUICC's own management interface whenever possible.__ In the future, there might be an option to exclude removable SIMs from being reported to the Android system.
-
-- Q: Can EasyEUICC manage my phone's internal eSIM?
-- A: No. For EasyEUICC to work, the eSIM chip MUST proactively grant access via its ARA-M field.
-
-- Q: Removable eSIMs? Are they a joke?
-- A: No, even though the name "removable embedded SIM" can sound like an oxymoron. In fact, there can be many advantages to these chips compared to fully embedded ones. For example, the ability to transfer eSIM profiles without carrier support or approval, or the ability to use eSIM on devices that do not and may never get the support, such as Wi-Fi hotspots.
+Releases can be found in the [release page](https://gitea.angry.im/jmp-sim/jmp-sim-manager/releases).
Copyright
===
diff --git a/app-unpriv/build.gradle.kts b/app-unpriv/build.gradle.kts
index 66a60b4..5eaa4df 100644
--- a/app-unpriv/build.gradle.kts
+++ b/app-unpriv/build.gradle.kts
@@ -32,6 +32,16 @@ android {
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}
+ flavorDimensions += "variant"
+ productFlavors {
+ create("jmp") {
+ dimension = "variant"
+ applicationId = "chat.jmp.simmanager"
+ // See: Signing.kt
+ signingConfig = signingConfigs.getByName("config")
+ isDefault = true
+ }
+ }
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
@@ -39,6 +49,10 @@ android {
kotlinOptions {
jvmTarget = "1.8"
}
+ dependenciesInfo {
+ // Disable dependency metadata -- breaks compatibility with F-Droid
+ includeInApk = false
+ }
}
dependencies {
diff --git a/app-unpriv/src/jmp/AndroidManifest.xml b/app-unpriv/src/jmp/AndroidManifest.xml
new file mode 100644
index 0000000..4ab370f
--- /dev/null
+++ b/app-unpriv/src/jmp/AndroidManifest.xml
@@ -0,0 +1,14 @@
+
+
+
+
\ No newline at end of file
diff --git a/app-unpriv/src/jmp/java/im/angry/openeuicc/JmpSimManagerApplication.kt b/app-unpriv/src/jmp/java/im/angry/openeuicc/JmpSimManagerApplication.kt
new file mode 100644
index 0000000..b69c2f0
--- /dev/null
+++ b/app-unpriv/src/jmp/java/im/angry/openeuicc/JmpSimManagerApplication.kt
@@ -0,0 +1,9 @@
+package im.angry.openeuicc
+
+import im.angry.openeuicc.di.JmpAppContainer
+
+class JmpSimManagerApplication : UnprivilegedOpenEuiccApplication() {
+ override val appContainer by lazy {
+ JmpAppContainer(this)
+ }
+}
\ No newline at end of file
diff --git a/app-unpriv/src/jmp/java/im/angry/openeuicc/di/JmpAppContainer.kt b/app-unpriv/src/jmp/java/im/angry/openeuicc/di/JmpAppContainer.kt
new file mode 100644
index 0000000..aae1bb7
--- /dev/null
+++ b/app-unpriv/src/jmp/java/im/angry/openeuicc/di/JmpAppContainer.kt
@@ -0,0 +1,13 @@
+package im.angry.openeuicc.di
+
+import android.content.Context
+
+class JmpAppContainer(context: Context) : UnprivilegedAppContainer(context) {
+ override val uiComponentFactory by lazy {
+ JmpUiComponentFactory()
+ }
+
+ override val customizableTextProvider by lazy {
+ JmpCustomizableTextProvider(context)
+ }
+}
\ No newline at end of file
diff --git a/app-unpriv/src/jmp/java/im/angry/openeuicc/di/JmpCustomizableTextProvider.kt b/app-unpriv/src/jmp/java/im/angry/openeuicc/di/JmpCustomizableTextProvider.kt
new file mode 100644
index 0000000..cc46cb3
--- /dev/null
+++ b/app-unpriv/src/jmp/java/im/angry/openeuicc/di/JmpCustomizableTextProvider.kt
@@ -0,0 +1,12 @@
+package im.angry.openeuicc.di
+
+import android.content.Context
+import im.angry.easyeuicc.R
+
+class JmpCustomizableTextProvider(private val context: Context) :
+ UnprivilegedCustomizableTextProvider(context) {
+ override val noEuiccExplanation: String
+ get() = context.getString(R.string.no_euicc_jmp)
+ override val profileSwitchingTimeoutMessage: String
+ get() = context.getString(R.string.enable_disable_timeout_jmp)
+}
\ No newline at end of file
diff --git a/app-unpriv/src/jmp/java/im/angry/openeuicc/di/JmpUiComponentFactory.kt b/app-unpriv/src/jmp/java/im/angry/openeuicc/di/JmpUiComponentFactory.kt
new file mode 100644
index 0000000..7bdbef0
--- /dev/null
+++ b/app-unpriv/src/jmp/java/im/angry/openeuicc/di/JmpUiComponentFactory.kt
@@ -0,0 +1,9 @@
+package im.angry.openeuicc.di
+
+import androidx.fragment.app.Fragment
+import im.angry.openeuicc.ui.JmpNoEuiccPlaceholderFragment
+
+class JmpUiComponentFactory : UnprivilegedUiComponentFactory() {
+ override fun createNoEuiccPlaceholderFragment(): Fragment =
+ JmpNoEuiccPlaceholderFragment()
+}
\ No newline at end of file
diff --git a/app-unpriv/src/jmp/java/im/angry/openeuicc/ui/JmpNoEuiccPlaceholderFragment.kt b/app-unpriv/src/jmp/java/im/angry/openeuicc/ui/JmpNoEuiccPlaceholderFragment.kt
new file mode 100644
index 0000000..b886116
--- /dev/null
+++ b/app-unpriv/src/jmp/java/im/angry/openeuicc/ui/JmpNoEuiccPlaceholderFragment.kt
@@ -0,0 +1,39 @@
+package im.angry.openeuicc.ui
+
+import android.content.Intent
+import android.net.Uri
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import im.angry.easyeuicc.R
+
+class JmpNoEuiccPlaceholderFragment : Fragment() {
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ val view = inflater.inflate(
+ R.layout.fragment_no_euicc_placeholder_jmp,
+ container,
+ false
+ )
+
+ view.findViewById(R.id.compatibility_check).setOnClickListener {
+ startActivity(Intent(requireContext(), CompatibilityCheckActivity::class.java))
+ }
+
+ view.findViewById(R.id.purchase_esim).setOnClickListener {
+ startActivity(
+ Intent(
+ Intent.ACTION_VIEW,
+ Uri.parse(getString(R.string.purchase_sim_url))
+ )
+ )
+ }
+
+ return view
+ }
+}
\ No newline at end of file
diff --git a/app-unpriv/src/jmp/res/drawable/ic_launcher_jmp_background.xml b/app-unpriv/src/jmp/res/drawable/ic_launcher_jmp_background.xml
new file mode 100644
index 0000000..dc69b44
--- /dev/null
+++ b/app-unpriv/src/jmp/res/drawable/ic_launcher_jmp_background.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
diff --git a/app-unpriv/src/jmp/res/drawable/ic_launcher_jmp_foreground.xml b/app-unpriv/src/jmp/res/drawable/ic_launcher_jmp_foreground.xml
new file mode 100644
index 0000000..bb29c7e
--- /dev/null
+++ b/app-unpriv/src/jmp/res/drawable/ic_launcher_jmp_foreground.xml
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app-unpriv/src/jmp/res/drawable/ic_launcher_jmp_monochrome.xml b/app-unpriv/src/jmp/res/drawable/ic_launcher_jmp_monochrome.xml
new file mode 100644
index 0000000..3942773
--- /dev/null
+++ b/app-unpriv/src/jmp/res/drawable/ic_launcher_jmp_monochrome.xml
@@ -0,0 +1,16 @@
+
+
+
+
diff --git a/app-unpriv/src/jmp/res/layout/fragment_no_euicc_placeholder_jmp.xml b/app-unpriv/src/jmp/res/layout/fragment_no_euicc_placeholder_jmp.xml
new file mode 100644
index 0000000..6253eb2
--- /dev/null
+++ b/app-unpriv/src/jmp/res/layout/fragment_no_euicc_placeholder_jmp.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app-unpriv/src/jmp/res/mipmap/ic_launcher_jmp.xml b/app-unpriv/src/jmp/res/mipmap/ic_launcher_jmp.xml
new file mode 100644
index 0000000..01cb1dd
--- /dev/null
+++ b/app-unpriv/src/jmp/res/mipmap/ic_launcher_jmp.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/app-unpriv/src/jmp/res/values-ja/strings.xml b/app-unpriv/src/jmp/res/values-ja/strings.xml
new file mode 100644
index 0000000..fdbd39d
--- /dev/null
+++ b/app-unpriv/src/jmp/res/values-ja/strings.xml
@@ -0,0 +1,6 @@
+
+
+ このデバイスで JMP eSIM Adapter を見つかりません。JMP eSIM Adapter をデバイスに挿入、または USB リーダーに経由し接続してください。
+ JMP eSIM Adapter を購入
+ eSIM チップがプロファイルの切り替えの待機中にタイムアウトしました。 SIM ツールキットの Tools -> Reboot を選択し、eSIM Adapter をリフレッシュしてください。
+
\ No newline at end of file
diff --git a/app-unpriv/src/jmp/res/values-zh-rCN/strings.xml b/app-unpriv/src/jmp/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..f74a5ce
--- /dev/null
+++ b/app-unpriv/src/jmp/res/values-zh-rCN/strings.xml
@@ -0,0 +1,6 @@
+
+
+ 没有在此设备上发现 JMP eSIM Adapter。请将其插入本设备或 USB 读卡器。
+ 购入 JMP eSIM Adapter
+ 等待 eSIM 芯片切换配置文件超时。请使用 SIM Toolkit 中的 Tools -> Reboot 手动刷新 eSIM Adapter。
+
\ No newline at end of file
diff --git a/app-unpriv/src/jmp/res/values/strings.xml b/app-unpriv/src/jmp/res/values/strings.xml
new file mode 100644
index 0000000..985b9d9
--- /dev/null
+++ b/app-unpriv/src/jmp/res/values/strings.xml
@@ -0,0 +1,10 @@
+
+
+ JMP SIM Manager
+ No JMP eSIM Adapter found on this device. Insert one into the device or through a USB card reader.
+ Buy JMP eSIM Adapter
+ https://jmp.chat/esim-adapter
+ https://gitea.angry.im/jmp-sim/jmp-sim-manager
+
+ Timed out waiting for the eSIM chip to switch profiles. Please manually refresh the eSIM adapter by going to SIM Toolkit, and select Tools -> Reboot.
+
\ No newline at end of file
diff --git a/app-unpriv/src/main/java/im/angry/openeuicc/UnprivilegedOpenEuiccApplication.kt b/app-unpriv/src/main/java/im/angry/openeuicc/UnprivilegedOpenEuiccApplication.kt
index 7993b50..f6702bd 100644
--- a/app-unpriv/src/main/java/im/angry/openeuicc/UnprivilegedOpenEuiccApplication.kt
+++ b/app-unpriv/src/main/java/im/angry/openeuicc/UnprivilegedOpenEuiccApplication.kt
@@ -7,7 +7,7 @@ import im.angry.openeuicc.util.*
import kotlinx.coroutines.runBlocking
import kotlin.system.exitProcess
-class UnprivilegedOpenEuiccApplication : OpenEuiccApplication() {
+open class UnprivilegedOpenEuiccApplication : OpenEuiccApplication() {
override val appContainer by lazy {
UnprivilegedAppContainer(this)
}
diff --git a/app-unpriv/src/main/java/im/angry/openeuicc/di/UnprivilegedAppContainer.kt b/app-unpriv/src/main/java/im/angry/openeuicc/di/UnprivilegedAppContainer.kt
index 4dbfe41..cfd9e43 100644
--- a/app-unpriv/src/main/java/im/angry/openeuicc/di/UnprivilegedAppContainer.kt
+++ b/app-unpriv/src/main/java/im/angry/openeuicc/di/UnprivilegedAppContainer.kt
@@ -2,7 +2,7 @@ package im.angry.openeuicc.di
import android.content.Context
-class UnprivilegedAppContainer(context: Context) : DefaultAppContainer(context) {
+open class UnprivilegedAppContainer(context: Context) : DefaultAppContainer(context) {
override val uiComponentFactory by lazy {
UnprivilegedUiComponentFactory()
}
diff --git a/app-unpriv/src/main/java/im/angry/openeuicc/di/UnprivilegedCustomizableTextProvider.kt b/app-unpriv/src/main/java/im/angry/openeuicc/di/UnprivilegedCustomizableTextProvider.kt
index 929ce84..807f66d 100644
--- a/app-unpriv/src/main/java/im/angry/openeuicc/di/UnprivilegedCustomizableTextProvider.kt
+++ b/app-unpriv/src/main/java/im/angry/openeuicc/di/UnprivilegedCustomizableTextProvider.kt
@@ -3,7 +3,7 @@ package im.angry.openeuicc.di
import android.content.Context
import im.angry.easyeuicc.R
-class UnprivilegedCustomizableTextProvider(private val context: Context) :
+open class UnprivilegedCustomizableTextProvider(private val context: Context) :
DefaultCustomizableTextProvider(context) {
override fun formatInternalChannelName(logicalSlotId: Int): String =
context.getString(R.string.channel_name_format_unpriv, logicalSlotId)
diff --git a/app-unpriv/src/main/java/im/angry/openeuicc/di/UnprivilegedUiComponentFactory.kt b/app-unpriv/src/main/java/im/angry/openeuicc/di/UnprivilegedUiComponentFactory.kt
index 06c489c..820e796 100644
--- a/app-unpriv/src/main/java/im/angry/openeuicc/di/UnprivilegedUiComponentFactory.kt
+++ b/app-unpriv/src/main/java/im/angry/openeuicc/di/UnprivilegedUiComponentFactory.kt
@@ -7,7 +7,7 @@ import im.angry.openeuicc.ui.UnprivilegedEuiccManagementFragment
import im.angry.openeuicc.ui.UnprivilegedNoEuiccPlaceholderFragment
import im.angry.openeuicc.ui.UnprivilegedSettingsFragment
-class UnprivilegedUiComponentFactory : DefaultUiComponentFactory() {
+open class UnprivilegedUiComponentFactory : DefaultUiComponentFactory() {
override fun createEuiccManagementFragment(slotId: Int, portId: Int): EuiccManagementFragment =
UnprivilegedEuiccManagementFragment.newInstance(slotId, portId)
diff --git a/fastlane/metadata/android/en-US/changelogs/278.txt b/fastlane/metadata/android/en-US/changelogs/278.txt
new file mode 100644
index 0000000..72e6eca
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/278.txt
@@ -0,0 +1 @@
+Initial public release of JMP SIM Manager.
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/280.txt b/fastlane/metadata/android/en-US/changelogs/280.txt
new file mode 100644
index 0000000..8b7ebc7
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/280.txt
@@ -0,0 +1 @@
+Initial Google Play + F-Droid release of JMP SIM Manager.
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/283.txt b/fastlane/metadata/android/en-US/changelogs/283.txt
new file mode 100644
index 0000000..501ca96
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/283.txt
@@ -0,0 +1,3 @@
+- Added support for USB card readers (standard T=0 CCID protocol required)
+- UI improvements (partially to accomodate USB readers)
+- Fixed numerous crashes and stability issues
diff --git a/fastlane/metadata/android/en-US/changelogs/285.txt b/fastlane/metadata/android/en-US/changelogs/285.txt
new file mode 100644
index 0000000..b12d293
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/285.txt
@@ -0,0 +1 @@
+Fix JNI crash on armv7 (32 bit) devices
diff --git a/fastlane/metadata/android/en-US/changelogs/287.txt b/fastlane/metadata/android/en-US/changelogs/287.txt
new file mode 100644
index 0000000..916b2f4
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/287.txt
@@ -0,0 +1,3 @@
+- Fixes compatibility on some devices which require slower APDU commands (e.g. Google Pixel series)
+- Optimize long-running tasks (downloading, switching, etc.) to rely on true background services
+- Miscellaneous bugfixes
diff --git a/fastlane/metadata/android/en-US/changelogs/292.txt b/fastlane/metadata/android/en-US/changelogs/292.txt
new file mode 100644
index 0000000..416ae51
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/292.txt
@@ -0,0 +1,4 @@
+- Brand new eSIM download wizard, with more detailed download progress and error diagnosis.
+- New menu option inside the main UI which brings up detailed information about each eSIM adapter, including their EID, free NVRAM space etc.
+- i18n translation for zh_CN and ja_JP (inherited from contribution to OpenEUICC)
+- Many miscellaneous bugfixes and improvements, including ones for USB readers.
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/294.txt b/fastlane/metadata/android/en-US/changelogs/294.txt
new file mode 100644
index 0000000..416ae51
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/294.txt
@@ -0,0 +1,4 @@
+- Brand new eSIM download wizard, with more detailed download progress and error diagnosis.
+- New menu option inside the main UI which brings up detailed information about each eSIM adapter, including their EID, free NVRAM space etc.
+- i18n translation for zh_CN and ja_JP (inherited from contribution to OpenEUICC)
+- Many miscellaneous bugfixes and improvements, including ones for USB readers.
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/full_description.txt b/fastlane/metadata/android/en-US/full_description.txt
new file mode 100644
index 0000000..4172865
--- /dev/null
+++ b/fastlane/metadata/android/en-US/full_description.txt
@@ -0,0 +1,5 @@
+JMP SIM Manager is a fully free and open-source companion app for the JMP eSIM Adapter. The JMP eSIM Adapter is a removable eSIM chip that enables any device, not just those with included eSIM chips, to make use of downloadable eSIMs.
+
+JMP SIM Manager provides management features such as adding, deleting, enabling, and disabling eSIM profiles for the adapter, and is the easiest option to manage your eSIM Adapter on compatible Android host devices. The manager app is not required once a profile has been downloaded and enabled on the adapter. In other words, you can use a compatible Android device to download your eSIM profile of choice onto the adapter, and then insert the adapter into any device -- Wi-Fi hotspots, dumb phones, laptops -- and the adapter will simply appear as a regular SIM card to those devices.
+
+This app also includes a quick compatibility check to determine whether your Android device can be used to manage a JMP eSIM Adapter. Although the eSIM Adapter will work with almost any device once an eSIM profile is loaded, management requires some specific features that may not be present on a small percentage of Android devices. However, even if your Android device is deemed incompatible, you can still manage the adapter from another Android device, using a PC/SC reader on a PC, or, as a final fallback, through the SIM Toolkit menu along with a self-hostable remote server to handle TLS termination.
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/images/icon.png b/fastlane/metadata/android/en-US/images/icon.png
new file mode 100644
index 0000000..9b6b965
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/icon.png differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png
new file mode 100644
index 0000000..f5c880e
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png differ
diff --git a/fastlane/metadata/android/en-US/short_description.txt b/fastlane/metadata/android/en-US/short_description.txt
new file mode 100644
index 0000000..3c0ed86
--- /dev/null
+++ b/fastlane/metadata/android/en-US/short_description.txt
@@ -0,0 +1 @@
+Companion app for the JMP eSIM Adapter
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/title.txt b/fastlane/metadata/android/en-US/title.txt
new file mode 100644
index 0000000..95b02c2
--- /dev/null
+++ b/fastlane/metadata/android/en-US/title.txt
@@ -0,0 +1 @@
+JMP SIM Manager
\ No newline at end of file
diff --git a/prepare_release.sh b/prepare_release.sh
new file mode 100755
index 0000000..af55e0c
--- /dev/null
+++ b/prepare_release.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+
+set -e
+
+new_version=$(($(git rev-list --first-parent --count HEAD) + 1))
+echo "New version code will be: ${new_version}"
+echo "${new_version}" > ./LAST_RELEASE_VERCODE
+
+changelog_path="./fastlane/metadata/android/en-US/changelogs"
+mkdir -p ${changelog_path}
+changelog_file="${changelog_path}/${new_version}.txt"
+echo "Creating new changelog: ${changelog_file}"
+touch "${changelog_file}"
+echo "Please populate the changelog above, then create ONE commit, and tag the release."
\ No newline at end of file