Skip to content

fix(android): isolate logger locale so it can't corrupt the host app#39

Merged
mibrahimdev merged 2 commits into
developfrom
fix/38-logger-locale-leak
Jul 2, 2026
Merged

fix(android): isolate logger locale so it can't corrupt the host app#39
mibrahimdev merged 2 commits into
developfrom
fix/38-logger-locale-leak

Conversation

@mibrahimdev

Copy link
Copy Markdown
Owner

Closes #38.

Problem

Opening the Sharingan logger (SharinganActivity, launched from the capture notification with FLAG_ACTIVITY_NEW_TASK) from a host app using per-app locales set to Arabic (RTL) rendered the logger as English text in an RTL frame and — worse — permanently corrupted the host: after closing the logger, the host app was stuck in English text with RTL layout.

Root cause

SharinganActivity is a plain ComponentActivity that neither pinned its own locale nor guarded the process-global one. On API 33+ the framework applied the host's per-app locale (ar → RTL) to the logger, and its config handling flipped the process-global Locale/LocaleList default to English, which leaked back to the host.

Fix

The logger is a locale-neutral surface: always English + LTR, and it must never read or mutate the host's locale. Two layers:

  • Activity (SharinganActivity)attachBaseContext pins an en/LTR Configuration via the non-mutating createConfigurationContext (never resources.updateConfiguration). A red test proved createConfigurationContext(en) resets LocaleList.getDefault() to English, so the activity now snapshots the host's LocaleList and restores it — right after the config context, and again in onDestroy — leaving the host untouched.
  • Compose (SharinganScreenContent) — wraps the stateless body in CompositionLocalProvider(LocalLayoutDirection provides Ltr) so the frame is LTR on every platform (including iOS, where the activity mechanism doesn't exist) and previews inherit it.

Tests

New instrumented regression LoggerLocaleLeakTest (@SdkSuppress(33)): pins the process to Arabic, opens/closes the logger, asserts the logger is LTR while open and every process-global locale knob (Locale.getDefault(), LocaleList.getDefault()) is still Arabic after.

Verified red→green on an API 34 emulator. Green: the new test, the :sharingan UI suite (8), CaptureNotificationE2eTest, :sharingan:testDebugUnitTest, and iosSimulatorArm64Test.

Notes

  • No new public API; apiCheck parity unaffected.
  • 3 files changed; no gradle/version-catalog changes.
  • Independently reviewed on two axes (locale-mechanism correctness + quality/conventions); all findings applied.

🤖 Generated with Claude Code

mibrahimdev and others added 2 commits July 1, 2026 17:21
Opening the Sharingan logger from a host that uses per-app locales
(e.g. AppCompat set to Arabic/RTL) rendered the logger in an RTL frame
and, worse, permanently corrupted the host: after closing the logger the
host was stuck in English text with RTL layout (issue #38).

Root cause: SharinganActivity is a plain ComponentActivity that neither
pins its own locale nor guards the process-global one. On API 33+ the
framework applied the host's per-app locale (ar -> RTL) to the logger,
and the logger's config handling flipped the process-global
Locale/LocaleList default to English, which leaked back to the host.

The logger is a locale-neutral surface: always English + LTR, and it must
never read or mutate the host's locale. Two-layer fix:

- Activity: attachBaseContext pins an en/LTR Configuration via the
  non-mutating createConfigurationContext (never resources.updateConfiguration).
- Compose: the stateless SharinganScreenContent forces
  LocalLayoutDirection = Ltr around its whole body, so the frame is LTR on
  every platform (including iOS) and in Studio previews.

The global-locale guard was needed: an instrumented test proved that
createConfigurationContext(en) resets LocaleList.getDefault() to English.
SharinganActivity now snapshots the host's LocaleList in attachBaseContext
and restores it (right after, and again in onDestroy), leaving the host's
locale untouched.

Verified red->green on an API 34 emulator with a new instrumented test that
pins the process to Arabic, opens/closes the logger, and asserts the logger
is LTR while open and every process-global JVM locale default is still
Arabic after. The test is @SdkSuppress(minSdkVersion = 33) since it drives
the API 33+ LocaleManager.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The locale-leak regression (LoggerLocaleLeakTest) and the other connected
suites (:sharingan UI tests, CaptureNotificationE2eTest) previously never
ran in CI — build.yml only covered JVM and iOS unit tests, so the issue-#38
fix was only verified by manual emulator runs. Add an `android` job
(reactivecircus/android-emulator-runner, API 34, KVM-accelerated ubuntu)
that runs both modules' connectedDebugAndroidTest and uploads reports on
failure, and correct the LoggerLocaleLeakTest KDoc that wrongly claimed CI
already ran emulators.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mibrahimdev mibrahimdev merged commit d07a934 into develop Jul 2, 2026
5 checks passed
@mibrahimdev mibrahimdev mentioned this pull request Jul 2, 2026
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.

[Bug] Opening Sharingan logger screen resets app locale to English while preserving RTL layout direction

1 participant