Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
e6c6b70
Fall back to full name for the snippet sender without first name
RankoR Aug 28, 2026
3f6c578
Enforce the foreign keys the schema declares
RankoR Aug 28, 2026
5206080
Show the formatted destination wherever a number is user-visible
RankoR Aug 28, 2026
296e53c
Show the audio attachment length before it is played
RankoR Aug 28, 2026
d762485
Move Jacoco setup to a buildSrc plugin to unbreak lint
RankoR Aug 28, 2026
96855e8
Never cluster a failed message with its neighbours
RankoR Aug 28, 2026
13036a5
Label outgoing messages with the timestamp the thread is sorted by
RankoR Aug 28, 2026
64da8ba
Show a no-results state when a recipient search matches nothing
RankoR Aug 28, 2026
ca303dc
Skip snoozed conversations when posting message notifications
RankoR Aug 28, 2026
7d522a0
Give each clear-notification PendingIntent a stable identity
RankoR Aug 28, 2026
8be6546
Notify every conversation with unseen messages, not just the newest
RankoR Aug 28, 2026
7eb5166
Show the MMS image in its notification
RankoR Aug 29, 2026
fc2d3ec
Give each notification button its own pending intent
RankoR Aug 29, 2026
30b9e06
Say which message failed in the failure notification
RankoR Aug 29, 2026
af7c72c
Resolve the self phone number from the carrier when the SIM lacks it
RankoR Aug 29, 2026
93deebf
Only accept a phone number as the self phone number
RankoR Aug 29, 2026
d1666b5
Announce pinned conversations in the order they are shown
RankoR Aug 29, 2026
8b2ff75
Decide selection toggles from the whole selection, not the first row
RankoR Aug 29, 2026
c5aa30d
Let the attachment menu take back without taking the keyboard down
RankoR Aug 29, 2026
a0c2c23
Fix the subscription settings test for state-driven dialog visibility
RankoR Aug 29, 2026
0d4885b
Warn that deleting a conversation cannot be undone
RankoR Aug 29, 2026
12800ed
Store the delivery report sent timestamp in milliseconds
RankoR Aug 29, 2026
af471eb
Run instrumented tests from a known device state
RankoR Aug 29, 2026
c05d7f5
Run instrumented tests on an Android 17 emulator image
RankoR Aug 29, 2026
939a2c4
Drop the dead null check in the message failure notification
RankoR Aug 31, 2026
f2e5935
Remember the group MMS dialog across configuration changes
RankoR Aug 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 38 additions & 12 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ jobs:
if-no-files-found: ignore

instrumented-tests:
name: Instrumented tests (Android 16 x86_64)
name: Instrumented tests (Android 17 x86_64)
runs-on: ubuntu-latest
timeout-minutes: 45

Expand All @@ -152,28 +152,49 @@ jobs:
java-version: 17
cache: gradle

- name: Build app and instrumented test APKs
run: >
./gradlew :app:assembleDebug :app:assembleDebugAndroidTest
--no-daemon --stacktrace --console=plain

- name: Enable KVM
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm

- name: Update Android command line tools
id: cmdline-tools
run: |
SDK="${ANDROID_HOME:-/usr/local/lib/android/sdk}"
yes | "$SDK/cmdline-tools/latest/bin/sdkmanager" --install 'cmdline-tools;latest' > /dev/null
if [ -d "$SDK/cmdline-tools/latest-2" ]; then
rm -rf "$SDK/cmdline-tools/latest"
mv "$SDK/cmdline-tools/latest-2" "$SDK/cmdline-tools/latest"
fi
version=$("$SDK/cmdline-tools/latest/bin/sdkmanager" --version 2>/dev/null | grep -Eo '^[0-9][0-9.]*' | head -1)
echo "version=$version" >> "$GITHUB_OUTPUT"

- name: Restore AVD cache
id: avd-cache
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: |
~/.android/avd/*
~/.android/adb*
key: avd-36-x86_64-default
key: avd-37.0-x86_64-google_apis-${{ steps.cmdline-tools.outputs.version }}

- name: Create AVD and generate snapshot for caching
if: steps.avd-cache.outputs.cache-hit != 'true'
uses: reactivecircus/android-emulator-runner@a421e43855164a8197daf9d8d40fe71c6996bb0d # v2.38.0
with:
api-level: 36
api-level: "37.0"
arch: x86_64
target: default
target: google_apis
cores: 4
ram-size: 4096M
heap-size: 576M
disk-size: 8G
force-avd-creation: false
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: false
Expand All @@ -182,18 +203,22 @@ jobs:
- name: Run instrumented tests and coverage gate
uses: reactivecircus/android-emulator-runner@a421e43855164a8197daf9d8d40fe71c6996bb0d # v2.38.0
with:
api-level: 36
api-level: "37.0"
arch: x86_64
target: default
target: google_apis
cores: 4
ram-size: 4096M
heap-size: 576M
disk-size: 8G
force-avd-creation: false
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: true
script: >
./gradlew :app:connectedDebugAndroidTest :app:jacocoAndroidTestVerification
-PandroidTestCoverage=true
-PandroidTestMinCoverage=80
-PandroidTestMinBranchCoverage=50
--no-daemon --stacktrace --console=plain
script: |
adb logcat -G 16M
./gradlew :app:connectedDebugAndroidTest :app:jacocoAndroidTestVerification -PandroidTestCoverage=true -PandroidTestMinCoverage=80 -PandroidTestMinBranchCoverage=50 --no-daemon --stacktrace --console=plain
rc=$?
adb logcat -d > logcat.txt
exit $rc

- name: Upload instrumented test reports
if: failure()
Expand All @@ -205,4 +230,5 @@ jobs:
app/build/outputs/androidTest-results/connected/
app/build/reports/jacoco/jacocoAndroidTestReport/
app/build/reports/androidTests/connected/
logcat.txt
if-no-files-found: ignore
11 changes: 7 additions & 4 deletions AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@
<uses-permission android:name="android.permission.READ_PROFILE"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<!-- Needed by SubscriptionManager#getPhoneNumber to resolve the self number from the
carrier or IMS when the SIM does not carry it -->
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS"/>

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
Expand Down Expand Up @@ -235,10 +238,10 @@
android:grantUriPermissions="true"
android:exported="false" />

<provider android:name=".datamodel.SharedMemoryImageProvider"
android:authorities="${applicationId}.datamodel.SharedMemoryImageProvider"
android:grantUriPermissions="true"
android:exported="false" />
<provider android:name=".datamodel.NotificationImageProvider"
android:authorities="${applicationId}.datamodel.NotificationImageProvider"
android:grantUriPermissions="true"
android:exported="false" />

<!-- Action Services -->
<service android:name=".datamodel.action.ActionServiceImpl"
Expand Down
3 changes: 1 addition & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ plugins {
alias(libs.plugins.detekt)
alias(libs.plugins.hilt)
jacoco
id("messaging.jacoco")
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.kotlin.parcelize)
alias(libs.plugins.kotlin.serialization)
Expand Down Expand Up @@ -243,5 +244,3 @@ dependencies {
androidTestImplementation(libs.mockk.android)
androidTestImplementation(libs.turbine)
}

apply(from = "jacoco.gradle.kts")
Loading