Skip to content

android: optimize split-tunnel app picker#808

Open
supfeer wants to merge 1 commit into
tailscale:mainfrom
supfeer:split-tunnel-picker-optimizations
Open

android: optimize split-tunnel app picker#808
supfeer wants to merge 1 commit into
tailscale:mainfrom
supfeer:split-tunnel-picker-optimizations

Conversation

@supfeer

@supfeer supfeer commented Jun 8, 2026

Copy link
Copy Markdown

Problem

The split-tunnel app picker can become expensive to render on devices with many installed apps.

Before this change, the picker:

  • loaded installed applications with PackageManager.GET_META_DATA;
  • loaded and converted app icons synchronously while composing each visible row;
  • used Material ListItem for every app row;
  • checked selected packages through a List.contains(...) call for each row;
  • always showed the full app list with no filtering;
  • kept selected apps mixed into the full list, making previously selected apps harder to review.

On devices with many installed applications, fast scrolling could stutter because row composition could trigger package manager icon lookups and bitmap conversion. In worse cases, repeated icon work during long downward scrolling could increase memory pressure and make the picker unstable enough to crash.

When that happened, apps near the end of the list could not be reached reliably, which meant users could be unable to add those packages to the split-tunnel include or exclude list.

The picker also had no filter/search control, so users with many installed apps had to scroll through the full list to find a specific package.

Changes

This change makes the split-tunnel app picker cheaper to render and easier to use.

Performance

  • Avoid requesting app metadata when enumerating installed apps.
  • Safely load app labels and skip apps that fail label loading.
  • Cache resized app icons in InstalledAppsManager.
  • Preload app icons off the UI thread in small batches.
  • Render app rows with a lighter fixed-height Row instead of ListItem.
  • Use contentType for LazyColumn.items.
  • Track selected package names as a Set for O(1) row selection checks.
  • Show a placeholder while an icon is still loading.

Filtering

  • Add a search field to filter the app list.
  • The filter matches both app display names and package names.
  • Filtering is case-insensitive and trims surrounding whitespace.
  • Filtering works together with the existing ordering rules: selected matches stay at the top, and Latin/English matches are shown before localized matches within each selected/unselected group.
  • When no apps match the filter, the picker shows the existing empty-results state.

Ordering

  • Keep selected apps at the top of the picker.
  • Within selected and unselected groups, show apps with Latin/English names before localized app names.
  • Preserve stable ordering inside each group.

Related issues

Updates tailscale/tailscale#19901.

Testing

Added unit coverage for the app ordering/filtering behavior, including:

  • selected apps sorted above unselected apps;
  • English/Latin app names sorted before localized names;
  • stable ordering within groups;
  • case-insensitive search by app name;
  • case-insensitive search by package name;
  • localized search queries;
  • blank and trimmed search queries;
  • no-result searches;
  • selected package names missing from the app list;
  • names with digit or punctuation prefixes;
  • volume ordering with 10,000 apps;
  • volume search with 10,000 apps.

Verified locally with:

./gradlew ktfmtCheck test assembleDebug

@supfeer supfeer force-pushed the split-tunnel-picker-optimizations branch from 0bd812a to f49bec7 Compare June 8, 2026 09:59
Updates tailscale/tailscale#19901

Signed-off-by: supfeer <supfeer@gmail.com>
@supfeer supfeer force-pushed the split-tunnel-picker-optimizations branch from f49bec7 to 80c74e8 Compare June 8, 2026 10:00
@supfeer supfeer marked this pull request as ready for review June 8, 2026 11:13
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