feat(screensaver): add real-time interactive photo drag & direction-aware slide transition - #166
Conversation
…e aplicaciones al espanol
starbrightlab
left a comment
There was a problem hiding this comment.
Thanks for this — the gesture/animation work is genuinely nicely built (the slide-completion math resuming from the live drag translationX and the snap-back reset are clean). But there are two blocking issues that would bite on real Portal hardware, so requesting changes.
Blockers
1. Main-thread I/O in the touch handler → crash. setupAdjacentDragBitmap() is called from onTouch ACTION_MOVE (main thread), and on a cache miss it falls back to a synchronous decode/fetch (PhotoFrameController.kt:246,251). For remote sources that's fetchRemoteImage on the UI thread → NetworkOnMainThreadException → launcher crash (and a crash on a home app clears the HOME preferred-activity association). It fires on the first swipe of any neighbor whose preload hasn't landed. The fallback must run on the io executor with the layer wired up in the posted ui continuation — never inline in ACTION_MOVE.
2. LruCache(8) is entry-count sized → OOM. LruCache<String,Bitmap>(8) (PhotoFrameController.kt:214) has no sizeOf override, so it's 8 entries regardless of pixel size. A 12MP original at inSampleSize=1 ≈ 48 MB ARGB_8888 × 8 ≈ ~300 MB retained, on top of the live layers + blur copies. That's a guaranteed OOM/heavy-GC regression on the RAM-limited Portal. Size the cache in bytes as a fraction of Runtime.maxMemory() (override sizeOf → bitmap.byteCount) and cap to prev/current/next (2–3 entries).
Should-fix
- Dwell timer races the drag —
ACTION_DOWN/MOVEnever cancel the auto-advance tick, so it can flipactiveLayerIndex/ resettranslationXmid-drag and move the wrong layer. Suspend the tick onACTION_DOWN/while dragging, reschedule on UP/snap-back. ACTION_CANCELcan trigger dismiss — UP and CANCEL share a branch (:300); a CANCEL with small dx/dy falls through to the tap test and callsonExit. GateonExittoACTION_UPonly.- Black gap on incomplete preload — if the incoming bitmap is null, the code still sets
incomingLayertranslation and the UP slide animates a blank/stale layer in. Guard the commit unless a real incoming bitmap was set.
Nits: no multi-touch/pointer-id handling; the index math + slide-duration calc are pure and worth a small unit test.
Happy to help once these are addressed — the core UX is worth landing.
…-tick race, and ACTION_CANCEL exit
…es and DecelerateInterpolator(1.8f) curve
Summary of Changes
This PR introduces real-time interactive touch gesture navigation and direction-aware slide transitions to the screensaver (
PhotoFrameController):1. Interactive 1:1 Touch Drag Navigation (
ACTION_MOVE)DecelerateInterpolator, or snaps back cleanly if released under threshold.2. Background Adjacent Photo Preloading (
LruCache)LruCache<String, Bitmap>for preloading adjacent (next & previous) photos on a background thread pool immediately after any photo displays.3. Preserved Auto-Dwell Transition
Verification & Unit Tests
./gradlew :app:testDebugUnitTest(BUILD SUCCESSFUL)../gradlew :app:assembleDebug).