Added
- Persistent Background TV File Sharing — Added persistent background TV file sharing service on Android TV / Fire TV, allowing paired mobile devices to browse TV storage even when UFM is closed on TV. Automatically starts when paired devices exist and stops when all are removed, with an on/off toggle in TV Settings (enabled by default).
- Expanded Video & Image Media Format Support — Added comprehensive support for viewing, managing, and routing previously unlisted video, Camera RAW, modern HDR stills, and graphic design/texture formats across Local, Network (SMB, SFTP, FTP, NFS, WebDAV, DLNA), and Cloud storage (Google Drive, OneDrive, Dropbox, S3) on Mobile and Android TV.
- Video Formats: Motion JPEG (
.mjpeg,.mjpg,.mjp), Apple video (.m4v,.qt,.3g2,.3gp2), Transport Streams (.m2ts,.mts,.m2t,.tp,.trp), DVD & MPEG streams (.vob,.evo,.mpg,.mpeg,.mpe,.m1v,.m2v,.mpv), Flash video (.f4v), Ogg media (.ogv,.ogm), RealMedia & Windows Media (.rm,.rmvb,.asf,.wm), and professional video (.mxf,.dv,.divx,.xvid,.mk3d). - Camera RAW & Photos: Comprehensive camera RAW photo support (
.cr3,.crw,.raf,.rw2,.orf,.pef,.ptx,.nrw,.srw,.srf,.sr2,.x3f,.erf,.kdc,.dcr,.k25,.mrw,.mos,.raw), modern HDR stills (.hif,.avifs,.hdr,.exr,.mpo,.jps,.pns), and graphic design/texture formats (.psd,.psb,.ai,.xcf,.kra,.clip,.tga,.targa,.dds,.wbmp,.cur,.ani,.pbm,.pgm,.ppm,.pnm,.pcx,.wmf,.emf). - Full Thumbnail Extraction: Guaranteed thumbnail generation and rendering across List and Grid views for all video formats via native FFmpeg frame decoding and Camera RAW formats via embedded Exif preview extraction across local and remote storage.
- Video Formats: Motion JPEG (
- Delete and Rename in Slide Show — Added Delete and Rename options when viewing photos in UFM Slide Show on both Mobile and Android TV. Delete supports moving to local Recycle Bin or permanent deletion across local, network shares (SMB, FTP, SFTP, SCP, NFS, TV Share), and cloud drives with automatic index updates and slide advancement. Rename prompts with a pre-filled filename dialog and renames files on disk or remote shares while maintaining tags, index records, and playlist state.
- Slideshow Speed Dialog — Added a dedicated Slideshow Speed picker dialog accessible from the 3-dots overflow menu on mobile and interval stepper controls on Android TV, offering selectable intervals from 0.5s to 5.0s.
- Multi-Slot Clipboard for Copy/Move — Added multi-item clipboard capability supporting up to 10 clipboard slots across Local, Network shares (SMB, FTP, SFTP, SCP, NFS, TV Share), and Cloud storage (Google Drive, OneDrive, Dropbox, S3, iDrive E2, WebDAV, rclone) on Mobile and Android TV.
- Slot Management & Combining — When copying or moving items while items already exist on the clipboard, a prompt allows appending to the active slot (combining local and network entries into unified slots) or creating a new slot. Capacity warnings notify users when 1 slot remains (at 9/10 slots) and prevent exceeding the 10-slot limit.
- ViewPager2 Tabbed Clipboard Sheet & TV Dialog — Replaced the single-list clipboard sheet with a
ViewPager2tabbed interface (TabLayoutwith swipeable slot pages on mobile, and D-pad accessible navigation on Android TV) allowing users to inspect items per slot, remove individual items or entire slots, paste a specific slot ("Paste this slot"), or paste all slots in batch ("Paste all").
- JPEG XL (.jxl) Image Support — Added full support for viewing and handling JPEG XL image files across all storage types (local, network, and cloud) and both device targets (mobile and Android TV).
.jxlfiles now display thumbnails in all file browser views (list, grid, compact, large grid), recycle bin, and SAF picker; open and navigate in the built-in image viewer and slideshow; re-encode correctly when saving edits; extract accurate dimensions and megapixel count in the File Properties sheet; generate network thumbnails over SMB, SFTP, SCP, FTP, NFS, WebDAV, and DLNA and all cloud providers (Google Drive, OneDrive, Dropbox, S3/iDrive E2, Box); appear under the Images filter chip, search/index category, Smart Sort, and PDF export. Powered byjxl-coder(io.github.awxkee, Apache-2.0 / BSD-3-Clause, API 21+).
Changed
- Settings Screen Categorization & Grouping — Reorganized the Settings hub across Mobile and Android TV into 10 structured card-grouped categories with section headers and polished glass container styling to improve discoverability and usability.
- Modernized Slide Show Layout (Mobile) — Redesigned the mobile Slide Show layout with a streamlined top toolbar (Back, Title/Info, Play/Pause, 3-dots Overflow Menu) and a modern glassmorphic bottom photo action bar containing Rotate Left/Right, Draw/Markup, Crop, Save (always visible), Rename, and Delete.
- Batch "Extract to New Folder" Isolation — When extracting multiple archives simultaneously using "Extract to New Folder" or "Extract & Select Folder", each archive is now extracted into its own dedicated subfolder named after the archive file across local, Shizuku, and network/cloud storage to prevent filename conflicts and mixed contents.
Fixed
- Fixed slideshow skipping videos prematurely after the image interval duration, ensuring videos play to completion before advancing to the next item.
- Fixed a bug where a play button, "2.5s" label, and interval seekbar were displayed across the bottom of images during regular photo viewing in UFM Slide Show.
- Fixed a false-positive ANR (App Freeze) report when the ANR watchdog samples the main thread inside the framework's per-glyph text-advance measurement while the Text Viewer measures its wrap-content content EditText during a normal window-measure pass — e.g. top frame
android.graphics.Paint.nGetRunCharacterAdvance/getRunCharacterAdvance(the native per-character advance computation) underTextLine.getRunAdvance/handleText/handleRun/measureRun/measure/metrics→Layout.getLineMax/getLineExtent→TextView.desired→TextView.onMeasure, measuring the content EditText (activity_text_viewer.xml/activity_text_viewer_tv.xml: ScrollView → HorizontalScrollView → LinearLayout → EditText,wrap_contentwidth), reached from a frame-draw traversal measure pass (Choreographer.doFrame→ViewRootImpl.performTraversals→measureHierarchy→performMeasure) — reported from a Hisilicon SMART_TV, SDK 34, app 1.8.6-GOOGLE. The text being measured is app-bounded (the viewer paginates at 16 KB per page and caps edit mode at 128 KB), the main thread is RUNNABLE and processing a fresh vsync frame at sample time, and the stack has zeroza.kilowatch.ultimatefilemanagerframes — the only non-platform frame is the bundled-libraryandroidx.appcompat.widget.ContentFrameLayoutin the window-decor chain, which breaks the pure-framework filter — so the >5 s block is device-side CPU starvation on the low-end TV (its DLNA/SSDP/HTTP-server background threads are all RUNNABLE) or a post-stall sample, not app business logic. TheAnrWatchdogThreadnow treats a main-thread stack whose top frame isPaint.getRunCharacterAdvance/nGetRunCharacterAdvance, with aTextLinemeasurement frame, aTextView.onMeasureframe, aHorizontalScrollViewframe and aScrollViewframe (the Text Viewer's wrap-content-in-horizontal-scroll layout), reached from a frame-draw traversal, with noza.kilowatch.ultimatefilemanagerframes and no framework blocking primitive anywhere on the stack, as a false positive and resets its heartbeat instead of writing a report. Genuine freezes keep an app frame on the stack (e.g. a main-threadsetTextof an unbounded document or a custom view measuring heavy text), a top frame that is not the per-glyph advance under theTextLine/TextView.onMeasurechain, a text measurement NOT reached from a ScrollView/HorizontalScrollView frame-draw traversal (e.g. a RecyclerView row), or a blocking primitive — and are still reported. - Fixed an ANR (App Freeze) when the main thread is blocked inside
android.graphics.Bitmap.nativeSetPixel/setPixelwhilePremiumShareTvActivity.onCreate(Android TV Web Share screen) generated the share URL's QR code synchronously on the main thread — reported from a Hisilicon HiDPTAndroid Hi3751V350, SDK 34, app 1.8.4-GOOGLE.QrCodeUtils.generateQrCode()built a 512×512 RGB_565Bitmapand wrote every pixel with a nestedfor (x) for (y) bitmap.setPixel(x, y, …)loop — 262,144 individual JNInativeSetPixelround-trips — which on a low-end TV exceeded the 5 s ANR threshold and froze the UI at launch (the report's ownDlnaSsdpListener,NanoHttpd Main Listener,WebShare-SSL-ProxyandDefaultDispatcher-worker-*threads are all RUNNABLE doing background work while the main thread grinds through per-pixel JNI calls).PremiumShareActivity(mobile Web Share) had the identical pattern insetupWebShareMode(), and both activities'updateConnectionInfo()regenerated the QR on the main thread on every network-state change.QrCodeUtils.generateQrCode()now fills anIntArrayofwidth * heightcolors in a plain Java loop and uploads the whole buffer with a singleBitmap.setPixels(...)native call instead of per-cellsetPixelcalls, and bothPremiumShareActivityandPremiumShareTvActivitynow generate and apply the QR off the main thread (lifecycleScope.launch(Dispatchers.Default)+withContext(Dispatchers.Main)), matching the existing OneDrive device-code QR pattern. The generated QR is pixel-identical (same row-major mapping, same black/white, same 1-module margin, same 512×512) and remains scannable; Web Share URL/PIN display, server startup/teardown, temporary-file cleanup, and network-change URL updates are unchanged — only the thread and the pixel-upload path changed. - Fixed a false-positive ANR (App Freeze) report when the ANR watchdog samples the main thread at the construction of a
java.util.concurrent.LinkedBlockingQueuewhile a freshly dispatched main-looper Runnable starts running — top framejava.util.concurrent.LinkedBlockingQueue.<init>(the bounded constructor that sets the queue's capacity fields and allocates its sentinel head Node; the no-arg constructor at line 245 delegates to theint capacityconstructor at line 255, so the sample carries one or two<init>frames), undercw.run(an R8-obfuscated non-platform Runnable) sitting directly onandroid.os.Handler.handleCallback— reported from a Xiaomi 23053RN02Y, SDK 35, app 1.8.0-GOOGLE. ALinkedBlockingQueue.<init>is a µs-scale bounded object allocation that cannot by itself occupy the main thread for 5 s, and the main looper is demonstrably processing a freshly dispatched message at sample time (Handler.handleCallbackdirectly below the Runnable'srun()), which a thread parked inside a >5 s block cannot do — so the >5 s block is device-side slowness / CPU starvation on the phone (the report's ownDlnaSsdpListener,NanoHttpd Main Listener,DefaultDispatcher-worker-*and HTTP-server threads are all RUNNABLE, starving the main thread) or a post-stall sample of the backlog the main looper drains after a genuine stall. The sampled frame is a platformjava.*class, so the existing fresh-run-entry filter (which requires a non-platform top frame) did not match, and the obfuscatedrun()is not platform-prefixed, so the pure-framework filter did not match either. TheAnrWatchdogThreadnow treats a main-thread stack whose top frame isLinkedBlockingQueue.<init>, whoserun()is a non-platform method sitting directly onHandler.handleCallback, with noHandler.postDelayedframe (the watchdog-heartbeat re-post shape, already handled) and no framework blocking primitive anywhere on the stack, as a false positive and resets its heartbeat instead of writing a report. Genuine freezes keep the main thread inside blocking work — a lock/wait/park, aBinderProxy.transact, a file/network/database I/O frame, or a top frame that is not the trivial queue constructor under that freshly-dispatchedrun()— and are still reported. - Fixed a crash (
java.lang.RuntimeException: Unable to create service … AdbRemoteForegroundService→SecurityException: Starting FGS with type connectedDevice … requires permissions … [android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE]) when starting the ADB Remote foreground service on Android 14+ (API 34+) builds whose merged manifest lacked theFOREGROUND_SERVICE_CONNECTED_DEVICEpermission — reported from a TV build (app 1.8.6-FOSS code 233, Android SDK 34).AdbRemoteForegroundServiceis declared in the shared main manifest withforegroundServiceType="connectedDevice"and started from the shared main source set (AdbWifiTransport.connect()), butandroid.permission.FOREGROUND_SERVICE_CONNECTED_DEVICEwas declared only in themobilesource-set manifest, sotv*variants merged the service without the permission and Android refused thestartForegroundcall, crashing the process fromonCreate(). The permission is now declared in the main manifest alongside the otherFOREGROUND_SERVICE_*permissions so every variant (mobile and TV) that can start the service holds it, andAdbRemoteForegroundService.onCreate()now guards thestartForegroundcall with a try/catch that logs and callsstopSelf()instead of crashing — the ADB remote connection/notification behaviour is unchanged when the permission is present. - Fixed a false-positive ANR (App Freeze) report when the ANR watchdog samples the main thread while the framework saves an Activity's instance state during a normal Activity stop — top frame
android.os.BaseBundle.unparcel(the parcel-parse thatBundle.putBundleperforms on the saved-instance-state bundle; on the AndroidX pathComponentActivity.onSaveInstanceState→SavedStateRegistry.performSave→outState.putBundle(...), and on an app Activity's own save path the app'sonSaveInstanceStateoverride callingoutState.putBundle(...)), underBundle.putBundle→ an R8-obfuscated non-platformonSaveInstanceStateoverride (the app or bundled-library Activity) →android.app.Activity.performSaveInstanceState→Instrumentation.callActivityOnSaveInstanceState→ActivityThread.callActivityOnSaveInstanceState/callActivityOnStop/performStopActivityInner/handleStopActivity→servertransaction.StopActivityItem.execute, thread state RUNNABLE — reported from a Google Pixel 6a, SDK 37, app 1.8.4-GOOGLE. The sampled work is the bounded unparcel of the saved-state bundle during the framework-driven stop-save:unparcelis O(saved-state size) bookkeeping the framework runs on every Activity stop, the app's own saved state is small (search-query strings, mode strings, boolean flags — the app has noputBundlecall and no large Parcelable in its saved state), and the main thread is RUNNABLE, so the frame cannot by itself occupy the main thread for 5 s on a normally-provisioned phone; the >5 s block is device-side slowness / CPU starvation or a post-stall sample of the backlog the main looper drains after a genuine stall. TheAnrWatchdogThreadfilter 57 (isSaveInstanceStateUnparcelStall) now treats a main-thread stack whose top frame isBaseBundle.unparcel, with aBundle.putBundleframe, a non-platformonSaveInstanceStateoverride frame, anandroid.app.Activity.performSaveInstanceStateframe and anActivityThreadstop-lifecycle frame (or aservertransaction.StopActivityItemframe), with noza.kilowatch.ultimatefilemanagerframes and no framework blocking primitive anywhere on the stack, as a false positive and resets its heartbeat instead of writing a report. Genuine freezes keep the main thread inside blocking work — a lock/wait/park, aBinderProxy.transact, a file/network/database I/O frame, an unobfuscated app frame on the stack, or saved-state work reached from app business logic outside the framework's Activity-stop save (e.g. an app-constructed huge Parcelable whose own write path blocks, which surfaces as a Parcel write frame, not aputBundleunparcel) — and are still reported. - Fixed a false-positive ANR (App Freeze) report when the ANR watchdog samples the main thread inside the framework's font-metrics measurement while a plain single-line TextView inside a scrollable content container measures its text during a normal window-measure pass — top frame
android.graphics.Paint.nGetFontMetricsInt/getFontMetricsInt(the native font-metrics read, the innermost frame of the framework's text measurement) underTextLine.expandMetricsFromPaint/handleText/handleRun/measureRun/measure/metrics→BoringLayout.isBoring(the framework's single-line fast-path check that a text run can use the optimized boring layout) →TextView.makeSingleLayout/makeNewLayout→TextView.onMeasure, measuring a TextView nested inside LinearLayout(s) within anandroidx.core.widget.NestedScrollView(a scrollable content/settings/about screen), reached from a frame-draw traversal measure pass (Choreographer.doFrame→ViewRootImpl.performTraversals→measureHierarchy→performMeasure) — reported from a Sony BRAVIA 4K UR3, SDK 29, app 1.8.6-GOOGLE.nGetFontMetricsIntis a bounded native call that returns the paint's font metrics, andBoringLayout.isBoringis an O(text-length) single-pass check the framework runs on every TextView relayout, so the measure of one screen's bounded text cannot by itself occupy the main thread for 5 s; the main thread is RUNNABLE and processing a fresh vsync frame at sample time, and the stack has zeroza.kilowatch.ultimatefilemanagerframes — the only non-platform frames are the bundled-libraryandroidx.core.widget.NestedScrollViewandandroidx.appcompat.widget.ContentFrameLayoutin the window-decor chain, which breaks the pure-framework filter — so the >5 s block is device-side CPU starvation on the low-end TV (its DLNA/SSDP/HTTP-server background threads are all RUNNABLE) or a post-stall sample, not app business logic. This is theBoringLayout.isBoring/font-metrics variant of the already-filtered Text Viewer per-glyph-advance report (filter 55,getRunCharacterAdvance/nGetRunCharacterAdvancetop frame + ScrollView/HorizontalScrollView layout), sampled at the single-line font-metrics read inside an androidxNestedScrollViewcontainer instead, so filter 55 did not match. TheAnrWatchdogThreadnow treats a main-thread stack whose top frame isPaint.getFontMetricsInt/nGetFontMetricsInt, with aBoringLayout.isBoringframe, aTextLinemeasurement frame, aTextView.makeSingleLayout/makeNewLayout/onMeasureframe, a scrollable-container frame (androidx.core.widget.NestedScrollViewor the frameworkScrollView/HorizontalScrollView), reached from a frame-draw traversal, with noza.kilowatch.ultimatefilemanagerframes and no framework blocking primitive anywhere on the stack, as a false positive and resets its heartbeat instead of writing a report. Genuine freezes keep the main thread inside app business logic — an app frame on the stack (e.g. a main-threadsetTextof an unbounded document or a custom view measuring heavy text), a top frame that is not the font-metrics read under the TextLine/BoringLayout.isBoring/TextView.onMeasuremeasure chain, a text measurement NOT reached from a scrollable-container frame-draw traversal (e.g. a RecyclerView row or a non-scrollable screen), or a blocking primitive (a lock, file/network/database I/O or binder frame) — and are still reported.