Skip to content

ADFA-6361: Keep the activity snapshot when a plugin passes its own inflater - #2130

Open
Daniel-ADFA wants to merge 2 commits into
stagefrom
fix/ADFA-6361-plugin-inflater-snapshot
Open

Daniel-ADFA wants to merge 2 commits into
stagefrom
fix/ADFA-6361-plugin-inflater-snapshot

Conversation

@Daniel-ADFA

@Daniel-ADFA Daniel-ADFA commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

ADFA-6361

Fixes StackOverflowError in PluginResourceContext.getResources() (GlitchTip, 14 events, from com.cogo.ai.assistant).

  • PluginFragmentHelper.getPluginInflater() no longer records an inflater's context as the plugin's activity when that context is the plugin context or wraps it. A plugin passing LayoutInflater.from(parent.context) from its own views made getResources() resolve to itself and recurse.
  • getPluginInflater() is the snapshot's only writer, and plugins compile against plugin-api without bundling it, so installed plugins get the fix from the host. No public API change (apiCheck passes).
  • PluginResourceContextActivitySnapshotTest: the plugin context and a ContextWrapper over it. Both fail without the fix (snapshot replaced; asserting resources first overflows the stack). plugin-manager tests gain Robolectric.
  • First commit is a Spotless reindent of PluginFragment.kt, whitespace only.

The file used four-space indentation, so touching it for the fix pulls the
whole file under the ratchet. Committed standalone.
…flater

PluginFragmentHelper.getPluginInflater() records the inflater's context as
the plugin's current activity, which PluginResourceContext uses to resolve
resources and the theme for plugins with a custom package ID. A plugin that
passes an inflater already running in its own context (for example
LayoutInflater.from(parent.context) in a RecyclerView adapter) recorded the
PluginResourceContext itself, so getResources() resolved to itself and
recursed until StackOverflowError (GlitchTip issue 7749649, 14 events,
com.cogo.ai.assistant).

getPluginInflater() now leaves the snapshot alone when the inflater's context
is the plugin context or wraps it. It is the only writer of the snapshot, and
plugins compile against plugin-api without bundling it, so installed plugins
get the fix from the host.

PluginResourceContextActivitySnapshotTest covers the plugin context and a
ContextWrapper over it; plugin-manager's unit tests gain Robolectric for it.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.

Tip: disable this comment in your organization's Code Review settings.

@coderabbitai

coderabbitai Bot commented Oct 11, 2026

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Essentials
  • Run ID: 5085f08e-cebd-401c-a570-9747284eb770

📥 Commits

Reviewing files that changed from the base of the PR and between dbeb7b2 and cdf8552.


📒 Files selected for processing (4)
  • plugin-api/src/main/kotlin/com/itsaky/androidide/plugins/base/PluginFragment.kt
  • plugin-manager/build.gradle.kts
  • plugin-manager/src/test/java/com/itsaky/androidide/plugins/manager/loaders/fakeplugin/R.java
  • plugin-manager/src/test/kotlin/com/itsaky/androidide/plugins/manager/loaders/PluginResourceContextActivitySnapshotTest.kt

Included review availability: This review used your included allowance. 3 included reviews remain after this review. Your included PR review attempts over the past 7 days set your current allowance at 5 reviews per hour.



📝 Summary
  • Prevented getPluginInflater() from replacing a plugin’s activity snapshot when the inflater context is the plugin context or a ContextWrapper around it. This avoids resource-resolution recursion in those cases.
  • Added Robolectric tests for the plugin context and a wrapping ContextWrapper. Added Robolectric as a plugin-manager test dependency and a fake-plugin R class for the test fixture.
  • Risk: isOrWraps() traverses ContextWrapper base contexts without cycle detection. A cyclic wrapper chain would not terminate.
  • Test execution status was not provided.

Walkthrough

getPluginInflater now checks whether the host context is the plugin context or wraps it before updating the activity context and theme snapshot. New Robolectric tests cover both context forms and verify the activity snapshot and plugin resources.

Changes

Plugin inflater activity snapshot

Layer / File(s) Summary
Check context before updating the snapshot
plugin-api/src/main/kotlin/com/itsaky/androidide/plugins/base/PluginFragment.kt
getPluginInflater now leaves the activity context and theme snapshot unchanged when the host context is the plugin context or wraps it. A recursive helper checks the ContextWrapper chain.
Test plugin context snapshot behavior
plugin-manager/build.gradle.kts, plugin-manager/src/test/java/com/itsaky/androidide/plugins/manager/loaders/fakeplugin/R.java, plugin-manager/src/test/kotlin/com/itsaky/androidide/plugins/manager/loaders/PluginResourceContextActivitySnapshotTest.kt
Robolectric tests cover inflater requests using the plugin context and a wrapper around it. They verify that the activity snapshot remains the application context and plugin resources remain the application resources.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix


Merge Risk: ⚪ Minimal · up to cdf85

The snapshot change and its tests show no identified issue that needs resolution before merge.

Pre-merge checks | Passed 4 | Failed 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 14 functions across 4 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description check Passed The description clearly explains the StackOverflowError fix, the activity snapshot behavior, and the added tests. It directly matches the changeset.
Title check Passed The title clearly identifies the main change: preserving the activity snapshot when a plugin provides its own inflater.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR

🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

A rabbit checked the context chain,
And left the snapshot just the same.
Wrapped or not, the tests now show
Which plugin resources flow below.
Then hopped away through clover green.

Comment @coderabbitai help to get the list of available commands.

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