Summary
android.nonTransitiveRClass=false in the root gradle.properties (line 28) disables non-transitive R classes for the app module, while modules/private-general-purpose/gradle.properties explicitly enables it (true) for the :core/:iap/general-purpose-app composite build. This inconsistency was introduced incidentally in #141 ("feat(export-transactions): implement in-app purchase") — the line was added with no explanation in the commit message, PR description, or review comments, as a side effect of that PR standing up the :core module and moving several shared resources into it.
Non-transitive R classes are AGP's default since 8.0 and Android Studio's default since Bumblebee — they shrink generated R classes, prevent resource-reference duplication across modules, and improve Gradle compilation avoidance (a module's Java/Kotlin compile task no longer needs to re-run just because a dependency's resources changed). Leaving it off for app forfeits those build-time wins project-wide.
Why it can't just be flipped today
app's compilation actually depends on the transitive resolution it disables. Specifically:
app/src/main/java/com/brainwallet/tools/adapter/TransactionListAdapter.java:181
convertView.arrowIcon.setImageResource(received ? R.drawable.arrow_down_bold_circle : R.drawable.arrow_up_bold_circle);
combined with the unqualified import com.brainwallet.R; at line 27. Both arrow_down_bold_circle and arrow_up_bold_circle were moved out of app/src/main/res/drawable and into modules/private-general-purpose/core/src/main/res/drawable in #141, but this call site was never updated to reference :core's own R class. It only compiles today because app's R class transitively inherits :core's drawable table.
This is the only call site in app that actually breaks under non-transitive R classes — I checked every resource :core contributes (5 drawables, 8 fonts, 9 colors) against what app/src/main/res also declares:
| Resource |
In :core? |
Duplicated in app? |
Breaks if flipped? |
drawable/arrow_back_24px |
✅ |
❌ |
core-only, unreferenced from app code — no |
drawable/arrow_down_bold_circle |
✅ |
❌ |
✅ yes |
drawable/arrow_up_bold_circle |
✅ |
❌ |
✅ yes |
drawable/brainwallet_logotype_color |
✅ |
✅ |
no — resolves locally |
drawable/brainwallet_logotype_white |
✅ |
✅ |
no — resolves locally |
font/ibm_plex_sans_* (all 8) |
✅ |
✅ (all 8) |
no — resolves locally |
color/white, cheddar, midnight, grape, chili, pesto |
✅ |
✅ |
no — resolves locally |
color/lavender |
✅ |
❌ |
core-only, unreferenced from app code — no |
color/border |
✅ |
❌ |
core-only, unreferenced from app code — no |
Two smells here
- The immediate blocker:
TransactionListAdapter.java:181 relies on implicit cross-module resource resolution instead of explicitly importing :core's R class.
- A milder duplication smell:
brainwallet_logotype_color/brainwallet_logotype_white, all 8 ibm_plex_sans_* fonts, and 6 of the 9 core colors (white, cheddar, midnight, grape, chili, pesto) are declared identically by name in both app/src/main/res and :core/src/main/res. Each module's copy currently shadows the other depending on resolution order — exactly the kind of duplicate-resource risk non-transitive R classes is designed to surface. Worth auditing whether these duplicates can be deleted from app now that :core is expected to be the shared source of these assets.
Proposed fix
- Update
TransactionListAdapter.java to reference :core's R class explicitly for the two arrow drawables, e.g.:
com.grunt.brainwallet.core.R.drawable.arrow_down_bold_circle
com.grunt.brainwallet.core.R.drawable.arrow_up_bold_circle
- Decide whether to delete the duplicate drawables/fonts/colors from
app/src/main/res in favor of :core's copies (or vice versa) — pick one source of truth.
- Flip
android.nonTransitiveRClass=true in root gradle.properties, matching modules/private-general-purpose/gradle.properties.
- Full rebuild +
./gradlew testBrainwalletDebugUnitTest to confirm nothing else was silently relying on transitive resolution outside the code paths grepped here.
References
Summary
android.nonTransitiveRClass=falsein the rootgradle.properties(line 28) disables non-transitive R classes for theappmodule, whilemodules/private-general-purpose/gradle.propertiesexplicitly enables it (true) for the:core/:iap/general-purpose-appcomposite build. This inconsistency was introduced incidentally in #141 ("feat(export-transactions): implement in-app purchase") — the line was added with no explanation in the commit message, PR description, or review comments, as a side effect of that PR standing up the:coremodule and moving several shared resources into it.Non-transitive R classes are AGP's default since 8.0 and Android Studio's default since Bumblebee — they shrink generated
Rclasses, prevent resource-reference duplication across modules, and improve Gradle compilation avoidance (a module's Java/Kotlin compile task no longer needs to re-run just because a dependency's resources changed). Leaving it off forappforfeits those build-time wins project-wide.Why it can't just be flipped today
app's compilation actually depends on the transitive resolution it disables. Specifically:app/src/main/java/com/brainwallet/tools/adapter/TransactionListAdapter.java:181combined with the unqualified
import com.brainwallet.R;at line 27. Botharrow_down_bold_circleandarrow_up_bold_circlewere moved out ofapp/src/main/res/drawableand intomodules/private-general-purpose/core/src/main/res/drawablein #141, but this call site was never updated to reference:core's own R class. It only compiles today becauseapp's R class transitively inherits:core's drawable table.This is the only call site in
appthat actually breaks under non-transitive R classes — I checked every resource:corecontributes (5 drawables, 8 fonts, 9 colors) against whatapp/src/main/resalso declares::core?app?drawable/arrow_back_24pxdrawable/arrow_down_bold_circledrawable/arrow_up_bold_circledrawable/brainwallet_logotype_colordrawable/brainwallet_logotype_whitefont/ibm_plex_sans_*(all 8)color/white, cheddar, midnight, grape, chili, pestocolor/lavendercolor/borderTwo smells here
TransactionListAdapter.java:181relies on implicit cross-module resource resolution instead of explicitly importing:core's R class.brainwallet_logotype_color/brainwallet_logotype_white, all 8ibm_plex_sans_*fonts, and 6 of the 9 core colors (white,cheddar,midnight,grape,chili,pesto) are declared identically by name in bothapp/src/main/resand:core/src/main/res. Each module's copy currently shadows the other depending on resolution order — exactly the kind of duplicate-resource risk non-transitive R classes is designed to surface. Worth auditing whether these duplicates can be deleted fromappnow that:coreis expected to be the shared source of these assets.Proposed fix
TransactionListAdapter.javato reference:core's R class explicitly for the two arrow drawables, e.g.:app/src/main/resin favor of:core's copies (or vice versa) — pick one source of truth.android.nonTransitiveRClass=truein rootgradle.properties, matchingmodules/private-general-purpose/gradle.properties../gradlew testBrainwalletDebugUnitTestto confirm nothing else was silently relying on transitive resolution outside the code paths grepped here.References
gradle.properties:28modules/private-general-purpose/gradle.properties:23app/src/main/java/com/brainwallet/tools/adapter/TransactionListAdapter.java:27,181