Skip to content

fix: Remove hidden and uninstalled apps from drawer folders - #7107

Open
pvolkov wants to merge 3 commits into
LawnchairLauncher:16-devfrom
pvolkov:fix/remove-hidden-from-drawer-folders
Open

fix: Remove hidden and uninstalled apps from drawer folders#7107
pvolkov wants to merge 3 commits into
LawnchairLauncher:16-devfrom
pvolkov:fix/remove-hidden-from-drawer-folders

Conversation

@pvolkov

@pvolkov pvolkov commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Description

Drawer folder membership stayed in Room after apps were hidden or uninstalled, so folder counts and contents could show stale entries until the folder was edited manually. This PR prunes folder items when apps are hidden or removed, filters hidden apps out of folder resolution, and cleans up leftover membership when the All Apps list updates.

Reasoning

Folder membership is stored separately from the apps store and was never pruned on hide/uninstall. Hidden apps also bypassed filtering when building drawer folders, so they could still appear inside a folder. Cleaning membership on those events (and as a safety net when the apps list refreshes) keeps counts and picker state consistent without requiring a manual folder edit.

Testing

  1. Create a drawer folder with several apps and note the item count.
  2. Uninstall one app from the folder → count decreases; the app is gone from the folder.
  3. Hide another app in the folder via Hidden apps → count decreases; the app no longer appears in the folder.
  4. Unhide that app → it does not reappear in the folder until added again.
  5. Open the folder editor / app picker and confirm counts and membership match what you see in the drawer.

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)

Summary by CodeRabbit

  • Bug Fixes
    • Cleaned up app folders by removing hidden, uninstalled, or invalid app entries.
    • Updated folders automatically when apps are hidden, uninstalled, or removed.
    • Prevented stale folder memberships from affecting folder contents and app counts.
    • Improved folder loading to exclude hidden apps and invalid entries.
    • Ensured folder contents stay synchronized after app removals and package updates.
    • Improved package matching to avoid removing similarly named apps unintentionally.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a6f0b597-0c9d-423c-af57-7ddce8e2a89a

📥 Commits

Reviewing files that changed from the base of the PR and between 236d8c6 and 6298d59.

📒 Files selected for processing (4)
  • lawnchair/src/app/lawnchair/allapps/LawnchairAlphabeticalAppsList.kt
  • lawnchair/src/app/lawnchair/data/folder/service/FolderDao.kt
  • lawnchair/src/app/lawnchair/data/folder/service/FolderService.kt
  • lawnchair/src/app/lawnchair/preferences2/PreferenceManager2.kt
🚧 Files skipped from review as they are similar to previous changes (4)
  • lawnchair/src/app/lawnchair/data/folder/service/FolderService.kt
  • lawnchair/src/app/lawnchair/data/folder/service/FolderDao.kt
  • lawnchair/src/app/lawnchair/allapps/LawnchairAlphabeticalAppsList.kt
  • lawnchair/src/app/lawnchair/preferences2/PreferenceManager2.kt

📝 Walkthrough

Walkthrough

This PR adds folder membership cleanup for hidden apps, removed packages, and malformed folder entries. It extends the folder DAO and service, wires cleanup into preference and package-removal flows, and prunes stale entries during All Apps folder loading and rendering.

Changes

Folder membership cleanup

Layer / File(s) Summary
Cleanup deletion APIs
lawnchair/src/app/lawnchair/data/folder/service/FolderDao.kt, lawnchair/src/app/lawnchair/data/folder/service/FolderService.kt
The DAO deletes items by exact component key or package boundary. The service adds suspend cleanup methods and a blocking Java helper.
Cleanup on hidden apps and package removal
lawnchair/src/app/lawnchair/preferences2/PreferenceManager2.kt, src/com/android/launcher3/model/PackageUpdatedTask.java
Hidden-app changes schedule component-key cleanup on MODEL_EXECUTOR. Package removal invokes synchronous package cleanup.
Folder pruning during All Apps processing
lawnchair/src/app/lawnchair/allapps/LawnchairAlphabeticalAppsList.kt
Folder loading asynchronously removes hidden or malformed memberships on the IO dispatcher. Folder rendering skips hidden component keys.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant HiddenAppsPreference
  participant PackageUpdatedTask
  participant LawnchairAlphabeticalAppsList
  participant FolderService
  participant FolderDao
  HiddenAppsPreference->>FolderService: removeItemsByComponentKeys(hidden component keys)
  PackageUpdatedTask->>FolderService: removePackagesBlocking(context, packages)
  LawnchairAlphabeticalAppsList->>FolderService: removeItemsByComponentKeys(stale keys)
  FolderService->>FolderDao: Delete matching folder items
Loading

Possibly related PRs

Suggested labels: bug-fix

Suggested reviewers: superdragonxd, mrsluffy

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: removing hidden and uninstalled apps from drawer folders.
Description check ✅ Passed The description covers the change, reasoning, testing steps, and marks the pull request as a bug fix.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lawnchair/src/app/lawnchair/allapps/LawnchairAlphabeticalAppsList.kt`:
- Around line 99-112: Update the stale-key filtering in the folder cleanup logic
around ComponentKey.fromString and appsStore.getApp so a missing appsStore entry
is removed only when the package/component is confirmed permanently removed for
that component user. Preserve folder membership for temporarily unavailable
apps, such as those removed during external-media unmount, while retaining
cleanup for explicitly hidden or invalid entries.

In `@lawnchair/src/app/lawnchair/data/folder/service/FolderDao.kt`:
- Around line 34-35: Update FolderDao.deleteFolderItemsByPackagePattern and its
FolderService caller to use a literal package-prefix comparison rather than LIKE
pattern matching, passing packageName directly so underscores and other package
characters remain literal.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2edbebc8-5ca6-4d1c-a84e-53cac5232f3a

📥 Commits

Reviewing files that changed from the base of the PR and between 3b65420 and efbeb3b.

📒 Files selected for processing (5)
  • lawnchair/src/app/lawnchair/allapps/LawnchairAlphabeticalAppsList.kt
  • lawnchair/src/app/lawnchair/data/folder/service/FolderDao.kt
  • lawnchair/src/app/lawnchair/data/folder/service/FolderService.kt
  • lawnchair/src/app/lawnchair/preferences2/PreferenceManager2.kt
  • src/com/android/launcher3/model/PackageUpdatedTask.java

Comment thread lawnchair/src/app/lawnchair/allapps/LawnchairAlphabeticalAppsList.kt Outdated
Comment on lines +34 to +35
@Query("DELETE FROM FolderItems WHERE item_info LIKE :packagePattern")
suspend fun deleteFolderItemsByPackagePattern(packagePattern: String)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Use a literal package-prefix comparison.

At Line 34, LIKE interprets _ in a package name as a wildcard. Removing com.example_a can also remove folder membership for a matching package such as com.exampleXa. Use a literal prefix comparison instead of a pattern match.

Proposed fix
-    `@Query`("DELETE FROM FolderItems WHERE item_info LIKE :packagePattern")
-    suspend fun deleteFolderItemsByPackagePattern(packagePattern: String)
+    `@Query`(
+        """
+        DELETE FROM FolderItems
+        WHERE substr(item_info, 1, length(:packageName) + 1) = :packageName || '/'
+        """,
+    )
+    suspend fun deleteFolderItemsByPackageName(packageName: String)

Update FolderService to pass packageName directly.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Query("DELETE FROM FolderItems WHERE item_info LIKE :packagePattern")
suspend fun deleteFolderItemsByPackagePattern(packagePattern: String)
`@Query`(
"""
DELETE FROM FolderItems
WHERE substr(item_info, 1, length(:packageName) + 1) = :packageName || '/'
""",
)
suspend fun deleteFolderItemsByPackageName(packageName: String)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lawnchair/src/app/lawnchair/data/folder/service/FolderDao.kt` around lines 34
- 35, Update FolderDao.deleteFolderItemsByPackagePattern and its FolderService
caller to use a literal package-prefix comparison rather than LIKE pattern
matching, passing packageName directly so underscores and other package
characters remain literal.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lawnchair/src/app/lawnchair/allapps/LawnchairAlphabeticalAppsList.kt (1)

106-109: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Serialize stale-folder cleanup with folder membership writes.

staleKeys is a snapshot, and the delete runs on Dispatchers.IO. A folder membership written after this snapshot can be deleted because removeItemsByComponentKeys only matches component keys. Revalidate the current hidden state before deletion, or perform cleanup in the same serialized update path that writes membership rows.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lawnchair/src/app/lawnchair/allapps/LawnchairAlphabeticalAppsList.kt` around
lines 106 - 109, Update the stale-folder cleanup in
LawnchairAlphabeticalAppsList so it does not delete membership rows based only
on the earlier staleKeys snapshot. Recheck the current hidden/membership state
at delete time, or move the cleanup into the same serialized update path used by
the folder membership writer in
FolderService.INSTANCE.get(context).removeItemsByComponentKeys. Keep the scope
limited to the launch/withContext(Dispatchers.IO) cleanup path and preserve
existing deletion behavior for entries that are still truly stale.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@lawnchair/src/app/lawnchair/allapps/LawnchairAlphabeticalAppsList.kt`:
- Around line 106-109: Update the stale-folder cleanup in
LawnchairAlphabeticalAppsList so it does not delete membership rows based only
on the earlier staleKeys snapshot. Recheck the current hidden/membership state
at delete time, or move the cleanup into the same serialized update path used by
the folder membership writer in
FolderService.INSTANCE.get(context).removeItemsByComponentKeys. Keep the scope
limited to the launch/withContext(Dispatchers.IO) cleanup path and preserve
existing deletion behavior for entries that are still truly stale.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7ee19d50-1732-466a-8f4a-271245ddcc9c

📥 Commits

Reviewing files that changed from the base of the PR and between efbeb3b and 4c6b5f4.

📒 Files selected for processing (3)
  • lawnchair/src/app/lawnchair/allapps/LawnchairAlphabeticalAppsList.kt
  • lawnchair/src/app/lawnchair/data/folder/service/FolderDao.kt
  • lawnchair/src/app/lawnchair/data/folder/service/FolderService.kt
🚧 Files skipped from review as they are similar to previous changes (1)
  • lawnchair/src/app/lawnchair/data/folder/service/FolderService.kt

pvolkov and others added 3 commits August 10, 2026 00:07
Keep folder membership and counts accurate when apps are hidden or uninstalled.

Co-authored-by: Cursor <cursoragent@cursor.com>
Avoid pruning temporarily unavailable apps from drawer folders, and delete by literal package prefix instead of LIKE.

Co-authored-by: Cursor <cursoragent@cursor.com>
Avoid deleting apps that were unhidden or re-added after the staleKeys snapshot was taken.

Co-authored-by: Cursor <cursoragent@cursor.com>
@pvolkov
pvolkov force-pushed the fix/remove-hidden-from-drawer-folders branch from 236d8c6 to 6298d59 Compare August 9, 2026 21:10
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