Skip to content

fix: bars hidden again over the video, LAN-only debug addresses, no leaked menu (#202, #203, #205) - #206

Merged
compot-dev merged 5 commits into
v2from
fix/bars-addresses-202
Oct 15, 2026
Merged

compot-dev merged 5 commits into
v2from
fix/bars-addresses-202

Conversation

@compot-dev

@compot-dev compot-dev commented Oct 15, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #202, fixes #203, fixes #205

#202 — bars over the video (Android 15)

Investigation. The app hid only navigationBars() with WindowInsetsController, once, in onCreate(); the status bar relied on the theme's windowFullscreen. Nothing re-applied it on resume or after another window (menu popup, dialogs, WebUI) had the focus. With target SDK 36 Android 15 draws edge to edge, so any bar the system leaves shown lies over the picture.

On the TECNO KM4 (Android 15) with v2.11 it did not reproduce: bars stayed hidden (dumpsys window: statusBars visible=false, navigationBars visible=false) from start, after top/right edge swipes (transient bars, gone after ~3 s), after the menu, Reset → Cancel, Settings URL editor with the keyboard → Cancel, WebUI → Close, Home and back, the notification shade, screen off/on, cold start and in the grid. So the OPPO (ColorOS) case is a system that brings the bars back and the app never asking again.

Fix. hideSystemBars() hides all system bars (systemBars()) with BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE on API 30+, and IMMERSIVE_STICKY | HIDE_NAVIGATION | FULLSCREEN before; it runs in onCreate(), onResume() and on every onWindowFocusChanged(true) (after the menu, dialogs and the WebUI). A decor insets listener hides bars again 3 s after they turn up persistently while the video has the focus (transient bars are not reported to the app). The WebUI dialog and its insets padding (#169, #180) are unchanged.

#203 — mobile-network addresses in the debug overlay

NetInfo.addresses() (overlay, /stats.json addresses) now goes through the pure NetInfo.lanAddresses(): cellular interfaces (rmnet*, rev_rmnet*, ccmni*, v4-*, clat*, seth*, pdp*, wwan*) are skipped, only private IPv4 (RFC 1918) is shown — loopback and link-local stay hidden as before, public/CGNAT are dropped — Wi-Fi (also a hotspot) first, then Ethernet, then the rest. The U view's hint and /stats.json udp.addresses keep every IPv4 address (NetInfo.udpAddresses(), unchanged behaviour): a pushed stream may come in over any of them. Unit tests with interface/address lists in DebugServerTest.

#205 — WindowLeaked menu popup

MenuManager.dismissAll() closes the menu popup, the URL editor / Reset dialog and the WebUI; called before finishAndRemoveTask() on Exit and in onDestroy().

Version 2.11 (36).

…eaked menu (#202, #203, #205)

- Viewing modes go back to full-screen immersive (status and navigation bars hidden,
  transient on swipe) on resume and on every window focus regain, so after the menu,
  dialogs and the WebUI too; bars that stay shown are hidden again after 3 s. Pre-R:
  IMMERSIVE_STICKY | HIDE_NAVIGATION | FULLSCREEN. WebUI keeps its insets padding.
- Debug addresses (overlay, /stats.json, UDP hint) list only private IPv4 addresses of
  non-cellular interfaces, Wi-Fi first, then Ethernet; pure NetInfo.lanAddresses() tested.
- Menu popup and the URL/Reset dialogs are dismissed before the activity finishes.
- 2.11 (36)

Fixes #202, fixes #203, fixes #205
@compot-dev compot-dev added the awaiting device test PR ready, merge only after testing on a real device label Oct 15, 2026
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Restore immersive video, filter LAN addresses, and dismiss menu windows

🐞 Bug fix 🧪 Tests ⚙️ Configuration changes 🕐 20-40 Minutes

Grey Divider

AI Description

• Rehide status and navigation bars when video viewing resumes or regains focus.
• Show only private IPv4 addresses from non-cellular interfaces in debug and UDP hints.
• Dismiss menu windows before exit and release version 2.11.
Diagram

graph TD
  Lifecycle["Activity lifecycle"] --> Decoder["Decoder activity"] --> Bars["System bars"]
  Decoder --> Menu["MenuManager"] --> Windows["Popup and dialogs"]
  Interfaces["Network interfaces"] --> NetInfo["NetInfo filter"] --> Outputs["Debug and UDP"]
  Decoder --> NetInfo
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Use ConnectivityManager for LAN address selection
  • ➕ Network capabilities can identify cellular transport without device-specific interface prefixes.
  • ➖ Adds Android network-service integration and may miss hotspot or other useful interfaces outside the active network.

Recommendation: Keep the interface-based filter for this fix: it preserves hotspot and Ethernet visibility and makes ordering and filtering straightforward to test. The cellular prefix list is a device-dependent heuristic worth revisiting if new interface names appear.

Files changed (5) +202 / -22

Bug fix (3) +134 / -18
Decoder.javaRestore immersive bars and clean up windows on exit +55/-11

Restore immersive bars and clean up windows on exit

• Hides both system bars on creation, resume, and focus regain, with a delayed retry when bars remain visible; older Android versions receive immersive fullscreen flags. Dismisses menu-owned windows before finishing and during destruction, and cancels the pending retry.

android/app/src/main/java/com/openipc/decoder/Decoder.java

MenuManager.javaTrack and dismiss menu-owned windows +29/-0

Track and dismiss menu-owned windows

• Tracks the URL editor and Reset confirmation dialogs and adds dismissAll() to close them, the menu popup, and the WebUI dialog during activity teardown.

android/app/src/main/java/com/openipc/decoder/MenuManager.java

NetInfo.javaLimit displayed addresses to non-cellular private IPv4 +50/-7

Limit displayed addresses to non-cellular private IPv4

• Routes interface enumeration through a testable LAN-address filter that excludes known cellular interface prefixes and non-private IPv4 addresses. Orders results Wi-Fi first, Ethernet second, and other interfaces last while removing duplicates.

android/app/src/main/java/com/openipc/decoder/NetInfo.java

Tests (1) +66 / -2
DebugServerTest.javaTest LAN address filtering and ordering +66/-2

Test LAN address filtering and ordering

• Adds cases for private-only IPv4 selection, cellular interface exclusion, Wi-Fi and Ethernet priority, stable ordering, and duplicate removal.

android/app/src/test/java/com/openipc/decoder/DebugServerTest.java

Other (1) +2 / -2
build.gradleBump Android app version to 2.11 +2/-2

Bump Android app version to 2.11

• Increments versionCode from 35 to 36 and versionName from 2.10 to 2.11 for the release containing these fixes.

android/app/build.gradle

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (2) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Local IPv6 addresses disappear 📎 Requirement gap ≡ Correctness
Description
NetInfo.isShown() accepts only IPv4 site-local addresses, so link-local and unique-local IPv6
addresses are discarded. lanAddresses() applies this filter to every interface used by the
overlay, /stats.json, and UDP hint, preventing eligible local addresses from being advertised.
Code

android/app/src/main/java/com/openipc/decoder/NetInfo.java[R88-90]

 static boolean isShown(InetAddress a) {
-        return a instanceof Inet4Address && !a.isLoopbackAddress() && !a.isLinkLocalAddress()
-                && !a.isAnyLocalAddress();
+        return a instanceof Inet4Address && a.isSiteLocalAddress();
 }
Evidence
The compliance rule permits private, link-local, or unique-local addresses, but isShown() requires
an IPv4 site-local address. lanAddresses() uses this predicate for all advertised addresses, and
the changed tests confirm link-local and unique-local inputs are rejected.

Restrict advertised debug server addresses
android/app/src/main/java/com/openipc/decoder/NetInfo.java[54-64]
android/app/src/main/java/com/openipc/decoder/NetInfo.java[83-90]
android/app/src/test/java/com/openipc/decoder/DebugServerTest.java[52-65]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The address filter rejects link-local and unique-local addresses even though the debug address lists must support eligible local Wi-Fi and Ethernet addresses in those ranges.
## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/NetInfo.java[83-90]
- android/app/src/test/java/com/openipc/decoder/DebugServerTest.java[52-65]
## Recommended Fix
Update `isShown()` to accept the required private IPv4, link-local, and unique-local address ranges while continuing to reject public, loopback, and carrier-grade NAT addresses. Add tests covering eligible IPv4 and IPv6 link-local and unique-local addresses.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. USB-tethered addresses are advertised 📎 Requirement gap ≡ Correctness
Description
NetInfo.lanAddresses() processes rank-2 interfaces after Wi-Fi and Ethernet instead of limiting
results to those two interface classes. A private address on an interface such as rndis0, a
bridge, or another non-cellular rank-2 interface therefore reaches the debug overlay and advertised
endpoints.
Code

android/app/src/main/java/com/openipc/decoder/NetInfo.java[R56-60]

+        for (int rank = 0; rank <= 2; rank++) {
+            for (Map.Entry<String, List<InetAddress>> e : byInterface.entrySet()) {
+                String name = e.getKey() == null ? "" : e.getKey().toLowerCase(Locale.ROOT);
+                if (isCellular(name) || rank(name) != rank) continue;
+                for (InetAddress a : e.getValue()) {
Evidence
The compliance rule requires advertised addresses to come only from Wi-Fi and Ethernet interfaces.
The changed implementation deliberately iterates ranks 0 through 2, where rank 2 is documented as
any other interface, and the changed test expects a private address from rndis0 to be advertised.

Restrict advertised debug server addresses
android/app/src/main/java/com/openipc/decoder/NetInfo.java[54-64]
android/app/src/main/java/com/openipc/decoder/NetInfo.java[75-80]
android/app/src/test/java/com/openipc/decoder/DebugServerTest.java[101-108]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The address collector includes rank-2 interfaces even though advertised addresses must come only from eligible Wi-Fi and Ethernet interfaces.
## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/NetInfo.java[54-80]
- android/app/src/test/java/com/openipc/decoder/DebugServerTest.java[101-112]
## Recommended Fix
Stop iterating rank 2, or explicitly exclude every interface that is not classified as Wi-Fi or Ethernet. Preserve Wi-Fi-before-Ethernet ordering and add a test proving that private addresses on `rndis`, bridge, and other non-Wi-Fi/non-Ethernet interfaces are omitted.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Valid UDP destinations disappear ✓ Resolved
Description
NetInfo.addresses() now uses lanAddresses(), which removes cellular-interface addresses and
non-private IPv4 addresses from the U-cell destination hint. When a device is reachable for pushed
RTP through one of those addresses, the receiver can still accept the stream, but the hint and UDP
stats omit the address the camera operator needs to configure.
Code

android/app/src/main/java/com/openipc/decoder/NetInfo.java[R58-61]

+                String name = e.getKey() == null ? "" : e.getKey().toLowerCase(Locale.ROOT);
+                if (isCellular(name) || rank(name) != rank) continue;
+                for (InetAddress a : e.getValue()) {
+                    if (isShown(a) && !out.contains(a.getHostAddress())) out.add(a.getHostAddress());
Evidence
The U-cell hint reads NetInfo.addresses(), and its fallback contains no destination address when the
list is empty. The new implementation filters that list, while the U-cell RTP socket binds without a
specific local address and has no sender restriction; the documented U-cell workflow relies on
showing the device address to send to.

android/app/src/main/java/com/openipc/decoder/NetInfo.java[36-46]
android/app/src/main/java/com/openipc/decoder/NetInfo.java[54-61]
android/app/src/main/java/com/openipc/decoder/NetInfo.java[83-90]
android/app/src/main/java/com/openipc/decoder/Decoder.java[916-947]
android/app/src/main/java/com/openipc/decoder/Decoder.java[1525-1530]
android/app/src/main/java/com/openipc/decoder/RtpListener.java[164-173]
android/app/src/main/java/com/openipc/decoder/RtpListener.java[200-216]
docs/usage.md[93-95]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The debug server needs LAN-only addresses, but the U-cell destination hint and UDP stats need every usable IPv4 destination for the wildcard-bound RTP receiver.
## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/NetInfo.java[36-46]
- android/app/src/main/java/com/openipc/decoder/Decoder.java[916-936]
- android/app/src/main/java/com/openipc/decoder/Decoder.java[1498-1503]
- android/app/src/main/java/com/openipc/decoder/Decoder.java[1525-1530]
## Recommended Fix
Keep the filtered list for debug-server URLs. Provide a separate enumeration of usable IPv4 interface addresses for the UDP hint and UDP stats, and update those callers to use it.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can hide the parts of a finding you never read, like the evidence or the agent prompt

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment on lines 88 to 90
static boolean isShown(InetAddress a) {
return a instanceof Inet4Address && !a.isLoopbackAddress() && !a.isLinkLocalAddress()
&& !a.isAnyLocalAddress();
return a instanceof Inet4Address && a.isSiteLocalAddress();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. Local ipv6 addresses disappear 📎 Requirement gap ≡ Correctness

NetInfo.isShown() accepts only IPv4 site-local addresses, so link-local and unique-local IPv6
addresses are discarded. lanAddresses() applies this filter to every interface used by the
overlay, /stats.json, and UDP hint, preventing eligible local addresses from being advertised.
Agent Prompt
## Issue description
The address filter rejects link-local and unique-local addresses even though the debug address lists must support eligible local Wi-Fi and Ethernet addresses in those ranges.

## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/NetInfo.java[83-90]
- android/app/src/test/java/com/openipc/decoder/DebugServerTest.java[52-65]

## Recommended Fix
Update `isShown()` to accept the required private IPv4, link-local, and unique-local address ranges while continuing to reject public, loopback, and carrier-grade NAT addresses. Add tests covering eligible IPv4 and IPv6 link-local and unique-local addresses.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Not changed: the shown addresses were IPv4 only before this PR as well (#87, #96). An IPv6 link-local URL needs a zone id (fe80::1%wlan0) that a browser cannot use, and ULA addresses are rare on the LANs this app runs in; a user types the IPv4 address. Only public/CGNAT IPv4 and mobile-data interfaces are dropped (#203).

Comment on lines +56 to +60
for (int rank = 0; rank <= 2; rank++) {
for (Map.Entry<String, List<InetAddress>> e : byInterface.entrySet()) {
String name = e.getKey() == null ? "" : e.getKey().toLowerCase(Locale.ROOT);
if (isCellular(name) || rank(name) != rank) continue;
for (InetAddress a : e.getValue()) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

2. Usb-tethered addresses are advertised 📎 Requirement gap ≡ Correctness

NetInfo.lanAddresses() processes rank-2 interfaces after Wi-Fi and Ethernet instead of limiting
results to those two interface classes. A private address on an interface such as rndis0, a
bridge, or another non-cellular rank-2 interface therefore reaches the debug overlay and advertised
endpoints.
Agent Prompt
## Issue description
The address collector includes rank-2 interfaces even though advertised addresses must come only from eligible Wi-Fi and Ethernet interfaces.

## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/NetInfo.java[54-80]
- android/app/src/test/java/com/openipc/decoder/DebugServerTest.java[101-112]

## Recommended Fix
Stop iterating rank 2, or explicitly exclude every interface that is not classified as Wi-Fi or Ethernet. Preserve Wi-Fi-before-Ethernet ordering and add a test proving that private addresses on `rndis`, bridge, and other non-Wi-Fi/non-Ethernet interfaces are omitted.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Kept on purpose: the debug server answers every private client, and a phone sharing its connection over USB (rndis) or a bridge is such a LAN, so its private address is reachable. They come last, after Wi-Fi and Ethernet, as #203 asks for the order; only mobile-data interfaces are left out.

Comment thread android/app/src/main/java/com/openipc/decoder/NetInfo.java
@compot-dev
compot-dev merged commit 753a4d1 into v2 Oct 15, 2026
3 checks passed
@compot-dev
compot-dev deleted the fix/bars-addresses-202 branch October 15, 2026 21:45
compot-dev pushed a commit that referenced this pull request Oct 15, 2026
A pushed RTP stream can arrive on any address, mobile data included; only the debug
page's addresses are LAN-only (#203).
compot-dev added a commit that referenced this pull request Oct 15, 2026
fix: bars hidden again over the video, LAN-only debug addresses, no leaked menu (#202, #203, #205)
compot-dev pushed a commit that referenced this pull request Oct 15, 2026
A pushed RTP stream can arrive on any address, mobile data included; only the debug
page's addresses are LAN-only (#203).
compot-dev added a commit that referenced this pull request Oct 15, 2026
fix: bars hidden again over the video, LAN-only debug addresses, no leaked menu (#202, #203, #205)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting device test PR ready, merge only after testing on a real device

Projects

None yet

2 participants