Skip to content

Commit 37e6782

Browse files
Temporarily re-add Android 5 support (#2925)
* Revert "Bump androidx.activity:activity-compose from 1.10.1 to 1.12.2" This reverts commit 307f0e1. * Revert "Bump androidx.compose:compose-bom from 2025.11.01 to 2025.12.01" This reverts commit a0fea79. * Revert "Remove Android 5 support" This reverts commit 2345785. * Update CHANGELOG
1 parent f58bdba commit 37e6782

File tree

12 files changed

+73
-20
lines changed

12 files changed

+73
-20
lines changed

.github/workflows/android.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,10 @@ jobs:
5050
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
5151
sudo udevadm control --reload-rules
5252
sudo udevadm trigger --name-match=kvm
53-
- name: Run instrumented tests (API 23)
53+
- name: Run instrumented tests (API 21)
5454
uses: ReactiveCircus/android-emulator-runner@v2
5555
with:
56-
api-level: 23
56+
api-level: 21
5757
arch: x86_64
5858
script: ./gradlew connected${{ matrix.flavor }}DebugAndroidTest
5959
- name: Run instrumented tests (API 35)

CHANGELOG.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
## Unreleased - 159
44

5-
Android 5.0 and 5.1 are no longer supported starting with this release. If you want to use Catima on these versions, please use version 2.41.1.
6-
75
- Fix change introduced in 2.41.0 that broke support for some scanners for non-UTF-8 barcodes
86

97
## v2.41.1 - 158 (2025-12-31)

app/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ android {
1717

1818
defaultConfig {
1919
applicationId = "me.hackerchick.catima"
20-
minSdk = 23
20+
minSdk = 21
2121
targetSdk = 36
2222
versionCode = 158
2323
versionName = "2.41.1"

app/src/main/java/protect/card_locker/CatimaAppCompatActivity.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,15 @@ protected void onPostCreate(@Nullable Bundle savedInstanceState) {
3838
Window window = getWindow();
3939
if (window != null) {
4040
boolean darkMode = Utils.isDarkModeEnabled(this);
41-
View decorView = window.getDecorView();
42-
WindowInsetsControllerCompat wic = new WindowInsetsControllerCompat(window, decorView);
43-
wic.setAppearanceLightStatusBars(!darkMode);
44-
window.setStatusBarColor(Color.TRANSPARENT);
41+
if (Build.VERSION.SDK_INT >= 23) {
42+
View decorView = window.getDecorView();
43+
WindowInsetsControllerCompat wic = new WindowInsetsControllerCompat(window, decorView);
44+
wic.setAppearanceLightStatusBars(!darkMode);
45+
window.setStatusBarColor(Color.TRANSPARENT);
46+
} else {
47+
// icons are always white back then
48+
window.setStatusBarColor(darkMode ? Color.TRANSPARENT : Color.argb(127, 0, 0, 0));
49+
}
4550
}
4651
// XXX android 9 and below has a nasty rendering bug if the theme was patched earlier
4752
Utils.postPatchColors(this);
@@ -61,4 +66,7 @@ protected void enableToolbarBackButton() {
6166
actionBar.setDisplayHomeAsUpEnabled(true);
6267
}
6368
}
69+
70+
public void onMockedRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
71+
}
6472
}

app/src/main/java/protect/card_locker/ListWidget.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ class ListWidget : AppWidgetProvider() {
100100
val foreground = if (Utils.needsDarkForeground(headerColor)) Color.BLACK else Color.WHITE
101101
setInt(R.id.item_container_foreground, "setBackgroundColor", headerColor)
102102
val icon = loyaltyCard.getImageThumbnail(context)
103-
// FIXME: The icon flow causes a crash up to Android 12L, so force anything below 33 down this path
103+
// setImageViewIcon is not supported on Android 5, so force Android 5 down the text path
104+
// FIXME: The icon flow causes a crash up to Android 12L, so SDK_INT is forced up from 23 to 33
104105
if (icon != null && Build.VERSION.SDK_INT >= 32) {
105106
setInt(R.id.item_container_foreground, "setBackgroundColor", foreground)
106107
setImageViewIcon(R.id.item_image, Icon.createWithBitmap(icon))

app/src/main/java/protect/card_locker/PermissionUtils.java

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ private static boolean needsStorageReadPermission(Activity activity) {
3434
* @return
3535
*/
3636
public static boolean needsCameraPermission(Activity activity) {
37+
// Android only introduced the runtime permission system in Marshmallow (Android 6.0)
38+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
39+
return false;
40+
}
41+
3742
return ContextCompat.checkSelfPermission(activity, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED;
3843
}
3944

@@ -44,14 +49,21 @@ public static boolean needsCameraPermission(Activity activity) {
4449
* @param activity
4550
* @param requestCode
4651
*/
47-
public static void requestStorageReadPermission(Activity activity, int requestCode) {
52+
public static void requestStorageReadPermission(CatimaAppCompatActivity activity, int requestCode) {
4853
String[] permissions = new String[]{ android.Manifest.permission.READ_EXTERNAL_STORAGE };
4954
int[] mockedResults = new int[]{ PackageManager.PERMISSION_GRANTED };
5055

5156
if (needsStorageReadPermission(activity)) {
5257
ActivityCompat.requestPermissions(activity, permissions, requestCode);
5358
} else {
54-
activity.onRequestPermissionsResult(requestCode, permissions, mockedResults);
59+
// FIXME: This points to onMockedRequestPermissionResult instead of to
60+
// onRequestPermissionResult because onRequestPermissionResult was only introduced in
61+
// Android 6.0 (SDK 23) and we and to support Android 5.0 (SDK 21) too.
62+
//
63+
// When minSdk becomes 23, this should point to onRequestPermissionResult directly and
64+
// the activity input variable should be changed from CatimaAppCompatActivity to
65+
// Activity.
66+
activity.onMockedRequestPermissionsResult(requestCode, permissions, mockedResults);
5567
}
5668
}
5769

@@ -62,14 +74,21 @@ public static void requestStorageReadPermission(Activity activity, int requestCo
6274
* @param activity
6375
* @param requestCode
6476
*/
65-
public static void requestCameraPermission(Activity activity, int requestCode) {
77+
public static void requestCameraPermission(CatimaAppCompatActivity activity, int requestCode) {
6678
String[] permissions = new String[]{ Manifest.permission.CAMERA };
6779
int[] mockedResults = new int[]{ PackageManager.PERMISSION_GRANTED };
6880

6981
if (needsCameraPermission(activity)) {
7082
ActivityCompat.requestPermissions(activity, permissions, requestCode);
7183
} else {
72-
activity.onRequestPermissionsResult(requestCode, permissions, mockedResults);
84+
// FIXME: This points to onMockedRequestPermissionResult instead of to
85+
// onRequestPermissionResult because onRequestPermissionResult was only introduced in
86+
// Android 6.0 (SDK 23) and we and to support Android 5.0 (SDK 21) too.
87+
//
88+
// When minSdk becomes 23, this should point to onRequestPermissionResult directly and
89+
// the activity input variable should be changed from CatimaAppCompatActivity to
90+
// Activity.
91+
activity.onMockedRequestPermissionsResult(requestCode, permissions, mockedResults);
7392
}
7493
}
7594
}

app/src/main/java/protect/card_locker/ScanActivity.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,14 @@ class ScanActivity : CatimaAppCompatActivity() {
543543
) {
544544
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
545545

546+
onMockedRequestPermissionsResult(requestCode, permissions, grantResults)
547+
}
548+
549+
override fun onMockedRequestPermissionsResult(
550+
requestCode: Int,
551+
permissions: Array<String>,
552+
grantResults: IntArray
553+
) {
546554
val granted =
547555
grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED
548556

app/src/main/java/protect/card_locker/UCropWrapper.kt

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,16 @@ class UCropWrapper : UCropActivity() {
4040
return
4141
}
4242

43-
val decorView = window.decorView
44-
val wic = WindowInsetsControllerCompat(window, decorView)
45-
wic.isAppearanceLightStatusBars = !darkMode
43+
if (Build.VERSION.SDK_INT >= 23) {
44+
val decorView = window.decorView
45+
val wic = WindowInsetsControllerCompat(window, decorView)
46+
wic.isAppearanceLightStatusBars = !darkMode
47+
} else if (!darkMode) {
48+
window.statusBarColor = ColorUtils.compositeColors(
49+
Color.argb(127, 0, 0, 0),
50+
window.statusBarColor
51+
)
52+
}
4653
}
4754

4855
private fun checkViews(darkMode: Boolean) {

app/src/main/java/protect/card_locker/contentprovider/CardsContentProvider.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,13 @@ public Cursor query(@NonNull final Uri uri,
7777
@Nullable final String selection,
7878
@Nullable final String[] selectionArgs,
7979
@Nullable final String sortOrder) {
80+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
81+
// Disable the content provider on SDK < 23 since it grants dangerous
82+
// permissions at install-time
83+
Log.w(TAG, "Content provider read is only available for SDK >= 23");
84+
return null;
85+
}
86+
8087
final Settings settings = new Settings(getContext());
8188
if (!settings.getAllowContentProviderRead()) {
8289
Log.w(TAG, "Content provider read is disabled");

app/src/main/java/protect/card_locker/importexport/CatimaImporter.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,6 @@ private LoyaltyCard importLoyaltyCard(CSVRecord record) throws FormatException {
459459
barcodeType = CatimaBarcode.fromName(unparsedBarcodeType);
460460
}
461461

462-
// This field did not exist in version 2.40.0 and before
463462
Charset barcodeEncoding = null;
464463
String unparsedBarcodeEncoding = CSVHelpers.extractString(DBHelper.LoyaltyCardDbIds.BARCODE_ENCODING, record, "");
465464
if (!unparsedBarcodeEncoding.isEmpty()) {

0 commit comments

Comments
 (0)