Skip to content

Fix camera preview/mesh overlay freeze after in-app language change - #26

Merged
guyiome merged 1 commit into
mainfrom
fix-camera-freeze-on-locale-change
Aug 20, 2026
Merged

Fix camera preview/mesh overlay freeze after in-app language change#26
guyiome merged 1 commit into
mainfrom
fix-camera-freeze-on-locale-change

Conversation

@guyiome

@guyiome guyiome commented Aug 20, 2026

Copy link
Copy Markdown
Owner

Summary

  • setApplicationLocales() recreates the Activity (documented AppCompat behavior), but MainViewModel survives it. initializeTracking()'s idempotency guard didn't distinguish that from a repeat call on the same Activity, so the camera pipeline stayed bound to the dead lifecycle -- CameraX unbinds on a DESTROYED owner, and on the OPTIMAL tier the ARCore session just stayed paused forever (its ON_START/ON_STOP observer only existed on the old owner). Only an app restart recovered.
  • initializeTracking() now compares the incoming LifecycleOwner by identity and calls the new rebindTrackingPipeline() when it differs -- rebuilds CameraController (genuinely lifecycle-bound) and re-registers the ON_START/ON_STOP observer, without redoing tier selection or FaceLandmarkerHelper setup.
  • ArCoreHeadPoseTracker is deliberately never rebuilt on a rebind -- it's Application-scoped already, so nothing to rebind. An earlier version of this fix rebuilt it anyway and hit a GLSurfaceView$GLThread.surfaceCreated() NPE (confirmed via adb logcat), since GLSurfaceView.setRenderer() must run before the view is attached to the window.
  • Not locale-specific: any config change Android doesn't find declared in android:configChanges (font scale, dark/light theme, multi-window resize...) recreates the Activity the same way.

Test plan

  • ./gradlew testDebugUnitTest assembleDebug lintDebug green.
  • Installed on device (ASUS_I001DC, OPTIMAL tier) -- reproduced the freeze first, then confirmed fixed after the correct version of this change. Root-caused via adb logcat across two iterations rather than guessing.

setApplicationLocales() recreates the Activity (documented AppCompat
behavior), but MainViewModel survives it -- initializeTracking()'s
idempotency guard (point 6) didn't distinguish that from a repeat
call on the same Activity, so the camera pipeline stayed bound to
the dead lifecycle: CameraX unbinds on a DESTROYED owner, and on the
OPTIMAL tier the ARCore session just stayed paused forever (its
ON_START/ON_STOP observer only existed on the old owner). Confirmed
on device (ASUS_I001DC, OPTIMAL tier) -- an app restart was the only
recovery.

initializeTracking() now compares the incoming LifecycleOwner by
identity and calls the new rebindTrackingPipeline() when it differs,
rebuilding CameraController (genuinely lifecycle-bound) and
re-registering the ON_START/ON_STOP observer, without redoing tier
selection or FaceLandmarkerHelper setup.

ArCoreHeadPoseTracker is deliberately never rebuilt here -- it's
Application-scoped already (built with getApplication(), not the
Activity), so nothing to rebind. Confirmed the hard way via adb
logcat: an earlier version of this fix rebuilt it anyway and hit
GLSurfaceView$GLThread.surfaceCreated() NPE, since GLSurfaceView's
setRenderer() (attachTo(), called from MainScreen's AndroidView
factory, which runs before window attachment) must run before the
surface is created -- a rebuilt tracker wasn't ready in time.

Not locale-specific: any config change Android doesn't find declared
in android:configChanges (font scale, dark/light theme, multi-window
resize...) recreates the Activity the same way.

See revue technique point 63 (local file, not tracked) for the full
diagnosis narrative across both attempts.
@guyiome
guyiome merged commit 14a021b into main Aug 20, 2026
3 checks passed
@guyiome
guyiome deleted the fix-camera-freeze-on-locale-change branch August 20, 2026 19:26
guyiome added a commit that referenced this pull request Sep 2, 2026
Patch release over v0.3.0: the new artist logo (#30), the camera
preview/overlay freeze fix on in-app language change (#26), the
security policy and issue templates (#24), and two dependency batches
(#25, #31).

Bumping versionName is not cosmetic here, it's required before
tagging: the in-app update checker compares BuildConfig.VERSION_NAME
against the latest GitHub release tag, so tagging v0.3.1 while the
build still reported 0.3.0 would show a permanent, unclearable
"update available" badge to users already running the newest build.

No README sync this time, unlike the v0.3.0 preparation: that one
tracked newly added features, whereas everything since is fixes plus
the logo. Checked that no tracked doc still credits the previous
placeholder logo.

Verified the built APK actually reports the new version (aapt2 dump
badging: versionCode='4' versionName='0.3.1') rather than assuming the
edit took effect. Unit tests, debug build and lint all pass.
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