Skip to content

feat(pro): include Pro on ExpressiveOS - #43

Merged
denson9874 merged 1 commit into
codex/pixel-parityfrom
claude/rom-bundled-pro
Nov 1, 2026
Merged

denson9874 merged 1 commit into
codex/pixel-parityfrom
claude/rom-bundled-pro

Conversation

@denson9874

Copy link
Copy Markdown
Owner

Requested by Daryl

Description

When Expressive Launcher runs on ExpressiveOS, every Pro feature is unlocked without a license. Licenses, trials and donations keep working everywhere else, and on ExpressiveOS too for anyone who wants to support development. This is the scaffold for "no pro gates when the launcher is bundled in the ROM". No release build is part of this PR.

Reasoning

  • Detection: the SHA-256 of the android package's platform signing certificate must equal ExpressiveOS's release platform cert be94c373…f48. On the build server that cert is vendor/evolution-priv/keys/platform.x509.pem, and the built framework-res.apk is signed with it. It differs from EvoX (2d5efc1e…), DerpFest (8d1eb9cd…) and the AOSP test key (c8a2e9bc…).
  • Why not a system property: root users can set one with resetprop, and integrity modules (Integrity Box) delete ro.evolution.*, which would switch Pro off for real ExpressiveOS users.
  • Why not "is a system app": any APK can be systemized with a KSU module.
  • Updates: a GitHub or Play update installed over the bundled copy keeps Pro, because the check is about the ROM, not the APK.
  • ProManager.isIncludedWithRom is computed once per process. isPro stays true when a license is missing, expires, fails verification or is deactivated, and no "trial ended" notice is shown.
  • ProGate unlocks regardless of a separately entered license's feature mask.
  • The banner and Pro sheet say "Included with ExpressiveOS" and hide the trial card. The Donate tab label, the Offline Key text and the Deactivate confirmation are worded to stay true on the ROM.
  • Leaving ExpressiveOS (for example restoring a launcher backup on another ROM): Pro features lock again, and saved settings stay.

Testing

  • ./gradlew testLawnWithQuickstepExpressiveDebugUnitTest --tests 'app.lawnchair.pro.*': 54/54 pass, including 8 new tests in RomEntitlementTest. They cover the cert match and mismatch, the real PackageManager path not throwing, Pro without a license, deactivate keeping Pro, trial expiry keeping Pro with no notice on the ROM, and trial expiry still returning to Free elsewhere.
  • spotlessApply was run on the changed files. spotlessCheck still fails on the base branch because of files this PR doesn't touch (ExpressiveCore.kt, FeedBridge.kt, …). Two remaining ktlint notes are in untouched code: INSTANCE naming in ProManager and multiple emitters in ProActiveContent.
  • An independent three-lens review (correctness, entitlement, tests/UI) confirmed 3 low-severity copy issues, all fixed in this PR, and refuted 3 others.
  • Not done: an on-device check on ExpressiveOS. Next is installing a debug build on cheetah and checking the banner, a gated screen, deactivate and the Offline Key tab.

Type of change

❌ Bug fix (A non-breaking change that fixes an issue)
✅ New feature (A non-breaking change that adds functionality)
❌ Breaking change (A fix or feature that would cause existing functionality to not work as expected)
❌ Refactor (A code change that neither fixes a bug nor adds a feature)
❌ Performance (A code change that improves performance)
❌ Style (Code style changes)
❌ Docs (Changes to documentation)
❌ Chore (Changes to the build process or other tooling)

🤖 Generated with Claude Code

When the launcher runs on ExpressiveOS, every Pro feature is unlocked
without a license. Detection compares the SHA-256 of the "android"
package's platform signing certificate with ExpressiveOS's release
platform cert (be94c373...), so a GitHub or Play update over the bundled
copy keeps Pro, while resetprop props or a systemized APK on another ROM
don't unlock it.

- ProManager: isIncludedWithRom; isPro stays true when a license is
  missing, expires, fails or is deactivated; no trial-ended notice.
- ProGate: unlocked on ExpressiveOS regardless of a license's mask.
- Banner and Pro sheet: "Included with ExpressiveOS", no trial card,
  Donate / Offline Key / Deactivate copy that is true on the ROM.
- RomEntitlementTest: 8 Robolectric tests.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@denson9874 denson9874 self-assigned this Oct 31, 2026

Copy link
Copy Markdown
Owner Author

check-style is red, but not from this PR.

The failing task is spotlessKotlinCheck, and every file it flags is outside this PR's diff — ExpressiveCore.kt, FeedBridge.kt, AllAppsSearchInput.kt, SearchItemBackground.kt, AllAppsCategoryTabs.kt, LazyColumnPreferenceGroup.kt, and (per the log) "59 other files." None of this PR's seven files appear in the list; spotlessApply was run on them before pushing.

So this is pre-existing, repo-wide formatting debt on the base branch (codex/pixel-parity), not a regression here. The honest fix is a separate ./gradlew spotlessApply cleanup PR against the base across those ~60 files — folding it into this scaffold would bury a 6-file feature under a 60-file reformat, so I've deliberately left it out.

The checks that actually exercise this change are green or running: build-debug-apk (PlayDebug) passed, the Github/Nightly builds are still running, and the Pro unit suite is 54/54 (8 new in RomEntitlementTest).


Generated by Claude Code

@denson9874
denson9874 marked this pull request as ready for review November 1, 2026 01:18
@denson9874
denson9874 merged commit 85cda5b into codex/pixel-parity Nov 1, 2026
6 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant