Skip to content

Fix: Adding custom games from USB OTG drives silently fails#1520

Open
sam1am wants to merge 2 commits into
utkarshdalal:masterfrom
sam1am:fix-usb-otg-volume-path
Open

Fix: Adding custom games from USB OTG drives silently fails#1520
sam1am wants to merge 2 commits into
utkarshdalal:masterfrom
sam1am:fix-usb-otg-volume-path

Conversation

@sam1am

@sam1am sam1am commented Jun 4, 2026

Copy link
Copy Markdown

Description

Adding a custom game from a USB OTG drive silently failed: getPathFromTreeUri hardcodes /storage/<uuid> when converting the picked document tree to a file path, but USB OTG drives on some devices (verified on a Samsung Galaxy Z Fold6, Android 16) are only mounted at the path reported by StorageVolume.getDirectory() — e.g. /mnt/media_rw/<uuid> — with no /storage/<uuid> view at all. The resolved path never existed (statENOENT), so CustomGameScanner.createLibraryItemFromFolder rejected the folder even with All files access granted.

The fix resolves the volume root via StorageManager by matching the volume UUID from the tree document ID, preferring /storage/<uuid> when it exists (SD cards) and falling back to StorageVolume.getDirectory() (USB OTG). Verified end-to-end on the affected device: a GOG game folder on a USB drive now adds and shows up in the library.

Diagnostics captured during testing on the affected device:

path: /storage/6A1F-93F0/Games/GOG/Blood West
Os.stat errno=2 (ENOENT)
isExternalStorageManager=true
volume uuid=6A1F-93F0 state=mounted removable=true primary=false dir=/mnt/media_rw/6A1F-93F0 desc=SANZANG

Two adjacent pre-existing issues noticed while debugging (not addressed here, happy to file separately):

  • On the modern flavor, the custom-game flow forwards users to the system All files access page, but the toggle there is permanently greyed out since the flavor doesn't declare MANAGE_EXTERNAL_STORAGE — a dead end. Only legacy can complete this flow.
  • When the selected folder fails validation, LibraryViewModel.addCustomGameFolder only logs and returns — the user gets no feedback.

Recording

https://www.youtube.com/shorts/mAWQXeKYIus

Type of Change

  • Bug fix
  • Performance / stability improvement
  • Compatibility improvements
  • Other (requires prior approval)

Checklist

  • If I have access to #code-changes, I have discussed this change there and it has been green-lighted. If I do not have access, I have still provided clear context in this PR. If I skip both, I accept that this change may face delays in review, may not be reviewed at all, or may be closed.
  • This change aligns with the current project scope (core functionality, stability, or performance). If not, it has been explicitly approved beforehand.
  • I have attached a recording of the change.
  • I have read and agree to the contribution guidelines in CONTRIBUTING.md.

🤖 Generated with Claude Code


Summary by cubic

Fixes custom-game folder import from USB OTG drives by resolving the correct storage volume root instead of hardcoding /storage/<uuid>. Users can now add games from OTG drives mounted only under /mnt/media_rw/<uuid> (e.g., Samsung devices).

  • Bug Fixes

    • Resolve volume root via StorageManager by matching the volume UUID; prefer /storage/<uuid> if it exists, else use StorageVolume.getDirectory(), then append the picked path.
    • Update getPathFromTreeUri to accept Context and pass it from the folder picker.
  • Refactors

    • Extract volume root resolution into a documented resolveVolumeRoot helper.

Written for commit 5b449e3. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes
    • Improved reliability of the custom game folder picker when accessing folders on secondary or non-primary storage volumes.
    • Better handling of various device storage layouts to reduce failed folder selections and improve path resolution across Android devices.

getPathFromTreeUri hardcoded /storage/<uuid> when converting a picked
document tree to a file path. USB OTG drives on some devices (e.g.
Samsung) are only mounted at the path reported by
StorageVolume.getDirectory() (such as /mnt/media_rw/<uuid>), with no
/storage view at all, so the resolved path never existed and adding a
custom game from such a drive silently failed.

Resolve the volume root via StorageManager by matching the volume UUID
from the tree document ID, preferring /storage/<uuid> when it exists.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR changes getPathFromTreeUri to accept an Android Context and resolve non-primary volume mount roots using StorageManager (falling back to /storage/ when present). The rememberCustomGameFolderPicker call site is updated to pass LocalContext.current.

Changes

Storage Volume Path Resolution

Layer / File(s) Summary
Resolve volume root helper
app/src/main/java/app/gamenative/ui/components/CustomGameFolderPicker.kt
Adds resolveVolumeRoot(context, volumeId) which prefers /storage/<volumeId> when present and otherwise queries StorageManager for the volume mount root.
API signature and path construction
app/src/main/java/app/gamenative/ui/components/CustomGameFolderPicker.kt
getPathFromTreeUri signature changed to getPathFromTreeUri(context, uri). Implementation now calls resolveVolumeRoot(context, volumeId) and returns volumeRoot combined with the document-relative path; old existence checks for /storage/<volumeId> candidates were removed.
Call site update
app/src/main/java/app/gamenative/ui/components/CustomGameFolderPicker.kt
rememberCustomGameFolderPicker updated to pass LocalContext.current into the new getPathFromTreeUri(context, uri) call.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

A rabbit hops with context bright,
Storage volumes now in sight.
No more guessing, paths ring true,
StorageManager knows what to do! 🐰📱

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarizes the main bug being fixed: adding custom games from USB OTG drives now works instead of silently failing.
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.
Description check ✅ Passed The pull request provides a comprehensive description covering the bug, root cause, solution, device testing, and a video demonstration.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 and usage tips.

@sam1am sam1am marked this pull request as ready for review June 4, 2026 16:00
@sam1am sam1am requested a review from utkarshdalal as a code owner June 4, 2026 16:00

@cubic-dev-ai cubic-dev-ai 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.

No issues found across 1 file

Re-trigger cubic

Addresses CodeRabbit docstring coverage warning.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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