Created
May 7, 2026 19:50
-
-
Save LethalMaus/550c64dd343000be40c3f7fbc59262e9 to your computer and use it in GitHub Desktop.
Dejavu cleaner runtime fix for article
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package dejavu.internal | |
| import android.app.Activity | |
| import android.app.Application | |
| import android.os.Bundle | |
| import androidx.compose.runtime.tooling.CompositionData | |
| import java.lang.ref.WeakReference | |
| import java.lang.reflect.Field | |
| import java.util.Collections | |
| import java.util.IdentityHashMap | |
| internal object Runtime { | |
| private var lastResumedRef: WeakReference<Activity>? = null | |
| private val knownActivities = mutableListOf<WeakReference<Activity>>() | |
| fun enable(app: Application) { | |
| discoverCurrentActivity()?.let { activity -> | |
| rememberActivity(activity) | |
| lastResumedRef = WeakReference(activity) | |
| ensureInspectionTag(activity) | |
| } | |
| val callbacks = object : Application.ActivityLifecycleCallbacks { | |
| override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { | |
| rememberActivity(activity) | |
| ensureInspectionTag(activity) | |
| } | |
| override fun onActivityStarted(activity: Activity) { | |
| rememberActivity(activity) | |
| ensureInspectionTag(activity) | |
| } | |
| override fun onActivityResumed(activity: Activity) { | |
| rememberActivity(activity) | |
| lastResumedRef = WeakReference(activity) | |
| ensureInspectionTag(activity) | |
| } | |
| override fun onActivityPaused(activity: Activity) = Unit | |
| override fun onActivityStopped(activity: Activity) = Unit | |
| override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) = Unit | |
| override fun onActivityDestroyed(activity: Activity) { | |
| forgetActivity(activity) | |
| } | |
| } | |
| app.registerActivityLifecycleCallbacks(callbacks) | |
| } | |
| internal fun currentCompositionsSnapshot(): Set<CompositionData> { | |
| if (lastResumedRef?.get() == null) { | |
| discoverCurrentActivity()?.let { activity -> | |
| rememberActivity(activity) | |
| lastResumedRef = WeakReference(activity) | |
| } | |
| } | |
| val out: MutableSet<CompositionData> = Collections.newSetFromMap(IdentityHashMap()) | |
| for (activity in snapshotCandidateActivities()) { | |
| ensureInspectionTag(activity) | |
| val root = activity.window?.decorView ?: continue | |
| collectCompositionDataFromView(root).forEach { any -> | |
| if (any is CompositionData) out.add(any) | |
| } | |
| if (out.isNotEmpty()) { | |
| if (lastResumedRef?.get() == null) { | |
| lastResumedRef = WeakReference(activity) | |
| } | |
| return out | |
| } | |
| } | |
| return out | |
| } | |
| private fun discoverCurrentActivity(): Activity? { | |
| return runCatching { | |
| val activityThreadClass = Class.forName("android.app.ActivityThread") | |
| val currentActivityThreadMethod = | |
| activityThreadClass.getDeclaredMethod("currentActivityThread").also { it.isAccessible = true } | |
| val activityThread = currentActivityThreadMethod.invoke(null) ?: return null | |
| val activitiesField: Field = | |
| activityThreadClass.getDeclaredField("mActivities").also { it.isAccessible = true } | |
| val activities = activitiesField.get(activityThread) as? Map<*, *> ?: return null | |
| var fallback: Activity? = null | |
| for (record in activities.values) { | |
| if (record == null) continue | |
| val recordClass = record.javaClass | |
| val activityField = recordClass.getDeclaredField("activity").also { it.isAccessible = true } | |
| val activity = activityField.get(record) as? Activity ?: continue | |
| fallback = fallback ?: activity | |
| val pausedField = runCatching { | |
| recordClass.getDeclaredField("paused").also { it.isAccessible = true } | |
| }.getOrNull() | |
| val stoppedField = runCatching { | |
| recordClass.getDeclaredField("stopped").also { it.isAccessible = true } | |
| }.getOrNull() | |
| val paused = (pausedField?.get(record) as? Boolean) ?: false | |
| val stopped = (stoppedField?.get(record) as? Boolean) ?: false | |
| if (!paused && !stopped) return activity | |
| } | |
| fallback | |
| }.getOrNull() | |
| } | |
| private fun rememberActivity(activity: Activity) { | |
| synchronized(knownActivities) { | |
| knownActivities.removeAll { ref -> | |
| val existing = ref.get() | |
| existing == null || existing === activity | |
| } | |
| knownActivities.add(WeakReference(activity)) | |
| } | |
| } | |
| private fun forgetActivity(activity: Activity) { | |
| synchronized(knownActivities) { | |
| knownActivities.removeAll { ref -> | |
| val existing = ref.get() | |
| existing == null || existing === activity | |
| } | |
| } | |
| if (lastResumedRef?.get() === activity) { | |
| lastResumedRef = null | |
| } | |
| } | |
| private fun snapshotCandidateActivities(): List<Activity> { | |
| val resumed = lastResumedRef?.get() | |
| val snapshot = synchronized(knownActivities) { | |
| knownActivities.mapNotNull { it.get() } | |
| } | |
| return buildList { | |
| if (resumed != null) add(resumed) | |
| snapshot.asReversed().forEach { activity -> | |
| if (activity !== resumed) add(activity) | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment