diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml
index f92f51a43..dcbba0597 100644
--- a/.github/ISSUE_TEMPLATE/bug-report.yml
+++ b/.github/ISSUE_TEMPLATE/bug-report.yml
@@ -1,7 +1,7 @@
 name: "\U0001F41E Bug report"
 description: Create a report to help us improve.
 title: "[Bug]: "
-labels: ["bug"]
+type: Bug  # Retained to categorize the issue as per organization-level type
 body:
   - type: markdown
     attributes:
@@ -70,7 +70,7 @@ body:
       required: false
   - type: textarea
     attributes:
-      label: Screen-shots
+      label: Screenshots
       description: Add screenshots related to the issue (if available). Can be created by pressing the Volume Down and Power Button at the same time on Android 4.0 and higher.
     validations:
       required: false
diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml
index a083225b7..bc8b03c9e 100644
--- a/.github/workflows/android.yml
+++ b/.github/workflows/android.yml
@@ -12,17 +12,17 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Checkout code
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
 
       - name: Set up JDK
-        uses: actions/setup-java@v3
+        uses: actions/setup-java@v4
         with:
-          distribution: "temurin"
-          java-version: 11
+          distribution: 'temurin'
+          java-version: '17'
 
       - name: Cache packages
         id: cache-packages
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             ~/.gradle/caches
@@ -37,7 +37,7 @@ jobs:
 
       - name: AVD cache
         if: github.event_name != 'pull_request'
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         id: avd-cache
         with:
           path: |
@@ -89,7 +89,7 @@ jobs:
         run: bash ./gradlew assembleBetaDebug --stacktrace
 
       - name: Upload betaDebug APK
-        uses: actions/upload-artifact@v3
+        uses: actions/upload-artifact@v4
         with:
           name: betaDebugAPK
           path: app/build/outputs/apk/beta/debug/app-*.apk
@@ -98,7 +98,17 @@ jobs:
         run: bash ./gradlew assembleProdDebug --stacktrace
 
       - name: Upload prodDebug APK
-        uses: actions/upload-artifact@v3
+        uses: actions/upload-artifact@v4
         with:
           name: prodDebugAPK
           path: app/build/outputs/apk/prod/debug/app-*.apk
+
+      - name: Create and PR number artifact
+        run: |
+          echo "{\"pr_number\": ${{ github.event.pull_request.number || 'null' }}}" > pr_number.json
+          
+      - name: Upload PR number artifact
+        uses: actions/upload-artifact@v4
+        with:
+          name: pr_number
+          path: ./pr_number.json
diff --git a/.github/workflows/build-beta.yml b/.github/workflows/build-beta.yml
new file mode 100644
index 000000000..8e1a26e15
--- /dev/null
+++ b/.github/workflows/build-beta.yml
@@ -0,0 +1,41 @@
+name: Build beta only
+
+on: [workflow_dispatch]
+
+jobs:
+  build:
+
+    runs-on: ubuntu-latest
+
+    steps:
+    - uses: actions/checkout@v4
+    - name: set up JDK 17
+      uses: actions/setup-java@v4
+      with:
+        java-version: '17'
+        distribution: 'temurin'
+        cache: gradle
+
+    - name: Access test login credentials
+      run: |
+        echo "TEST_USER_NAME=${{ secrets.TEST_USER_NAME }}" >> local.properties
+        echo "TEST_USER_PASSWORD=${{ secrets.TEST_USER_PASSWORD }}" >> local.properties
+
+    - name: Grant execute permission for gradlew
+      run: chmod +x gradlew
+
+    - name: Set env
+      run: echo "COMMIT_SHA=$(git log -n 1 --format='%h')" >> $GITHUB_ENV
+
+    - name: Generate betaDebug APK
+      run: ./gradlew assembleBetaDebug --stacktrace
+
+    - name: Rename betaDebug APK
+      run: mv app/build/outputs/apk/beta/debug/app-*.apk app/build/outputs/apk/beta/debug/apps-android-commons-betaDebug-$COMMIT_SHA.apk
+
+    - name: Upload betaDebug APK
+      uses: actions/upload-artifact@v4
+      with:
+        name: apps-android-commons-betaDebugAPK-${{ env.COMMIT_SHA }}
+        path: app/build/outputs/apk/beta/debug/*.apk
+        retention-days: 30
diff --git a/.github/workflows/comment_artifacts_on_PR.yml b/.github/workflows/comment_artifacts_on_PR.yml
new file mode 100644
index 000000000..ee4ae7c46
--- /dev/null
+++ b/.github/workflows/comment_artifacts_on_PR.yml
@@ -0,0 +1,96 @@
+name: Comment Artifacts on PR
+
+on:
+  workflow_run:
+    workflows: [ "Android CI" ]
+    types: [ completed ]
+
+permissions:
+  pull-requests: write
+  contents: read
+
+concurrency:
+  group: comment-${{ github.event.workflow_run.id }}
+  cancel-in-progress: true
+
+jobs:
+  comment:
+    runs-on: ubuntu-latest
+    if: ${{ github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'pull_request' }}
+    steps:
+      - name: Download and process artifacts
+        uses: actions/github-script@v7
+        with:
+          github-token: ${{ secrets.GITHUB_TOKEN }}
+          script: |
+            const fs = require('fs');
+            const runId = context.payload.workflow_run.id;
+
+            const allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
+              owner: context.repo.owner,
+              repo: context.repo.repo,
+              run_id: runId,
+            });
+
+            const prNumberArtifact = allArtifacts.data.artifacts.find(artifact => artifact.name === "pr_number");
+            if (!prNumberArtifact) {
+              console.log("pr_number artifact not found.");
+              return;
+            }
+
+            const download = await github.rest.actions.downloadArtifact({
+              owner: context.repo.owner,
+              repo: context.repo.repo,
+              artifact_id: prNumberArtifact.id,
+              archive_format: 'zip',
+            });
+
+            fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/pr_number.zip`, Buffer.from(download.data));
+            const { execSync } = require('child_process');
+            execSync('unzip -q pr_number.zip -d ./pr_number/');
+            fs.unlinkSync('pr_number.zip');
+
+            const prData = JSON.parse(fs.readFileSync('./pr_number/pr_number.json', 'utf8'));
+            const prNumber = prData.pr_number;
+
+            if (!prNumber || prNumber === 'null') {
+              console.log("No valid PR number found in pr_number.json. Skipping.");
+              return;
+            }
+
+            const artifactsToLink = allArtifacts.data.artifacts.filter(artifact => artifact.name !== "pr_number");
+            if (artifactsToLink.length === 0) {
+              console.log("No artifacts to link found.");
+              return;
+            }
+
+            const comments = await github.rest.issues.listComments({
+              owner: context.repo.owner,
+              repo: context.repo.repo,
+              issue_number: Number(prNumber),
+            });
+            
+            const oldComments = comments.data.filter(comment => 
+              comment.body.startsWith("✅ Generated APK variants!")
+            );
+            for (const comment of oldComments) {
+              await github.rest.issues.deleteComment({
+                owner: context.repo.owner,
+                repo: context.repo.repo,
+                comment_id: comment.id,
+              });
+              console.log(`Deleted old comment ID: ${comment.id}`);
+            };
+            
+            const commentBody = `✅ Generated APK variants!\n` + 
+            artifactsToLink.map(artifact => {
+                const artifactUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}/artifacts/${artifact.id}`;
+                return `- 🤖 [Download ${artifact.name}](${artifactUrl})`;
+            }).join('\n');
+
+            await github.rest.issues.createComment({
+              owner: context.repo.owner,
+              repo: context.repo.repo,
+              issue_number: Number(prNumber),
+              body: commentBody
+            });
diff --git a/.gitignore b/.gitignore
index 418e4c380..7fa4767a7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -43,3 +43,8 @@ app/src/main/jniLibs
 #https://docs.opencv.org/3.3.0/
 /libraries/opencv/javadoc/
 captures/*
+
+# Test and other output
+app/jacoco.exec
+app/CommonsContributions
+app/.*
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index f277755ba..ea0cb3b07 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -16,6 +16,7 @@