Skip to content

2.20.0: the touch-only actions on a D-pad remote (#263) - #264

Open
compot-dev wants to merge 3 commits into
v2from
feat/remote-actions-263
Open

compot-dev wants to merge 3 commits into
v2from
feat/remote-actions-263

Conversation

@compot-dev

@compot-dev compot-dev commented Nov 2, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #263.

Four actions existed only as touch gestures, so a box with a D-pad remote could not reach them. With the menu closed the remote now does what the gestures do.

Keys (menu closed)

Key Single view Multi-view
short OK open the menu (now on release) open the menu (now on release)
held OK, or Menu save a screenshot (the long press) the selected cell's sound on / off (the long press on a cell)
held Up / Down zoom in / out, 1×–5×; down to 1× is the reset —
short arrow pan the zoomed picture move the yellow selection frame
ZOOM, CH, PAGE, + / − zoom in / out by 1.25× —
  • The menu opens when OK is released, so that OK can be held; onKeyLongPress needs the press tracked. An OK that closed the menu, or was pressed in it, opens nothing on release (the Save report: stats.json and the log as one file, from the app and from the debug page #207 case).
  • Menu is the fallback for remotes whose OK has no long press, as on Debug in the menu (Save report: stats.json and the log as one file, from the app and from the debug page #207).
  • A key zoom keeps the point at the centre of the screen there (a remote has no point to zoom into).
  • Multi-view: the first arrow shows the frame on the cell whose sound plays (or the first), the next ones move it; it stops at the edges and goes away after 4 s. The U cell can be selected, and a held OK on it says that it has video only.
  • RemoteKeys holds the key mapping and the zoom, pan and grid arithmetic (RemoteKeysTest).
  • docs/usage.md ("Gestures and keys", "Remote control", multi-view audio, screenshots), the three READMEs and the CHANGELOG describe it. Version 2.20.0 (a feature).

Checks

  • Local build in Docker (compot/android), as in CI: testDebugUnitTest, lintDebug (no new findings), assembleRelease. APK +0.8 KB.
  • Android TV 16 emulator (API 36, 1920×1080), D-pad input only (input keyevent), a lab camera in the single view and a 2×2 grid:
    • short OK opens the menu, Back closes it; the menu is still driven by the D-pad (slot 2 chosen, Grid turned on with it);
    • CH+ ×3 zooms in, Left/Up pan to the top left, CH− back to 1× restores the full picture;
    • a held Up zooms (one key repeat = one step); a held OK saves Pictures/OpenIPC/Screenshot_….png and opens no menu;
    • grid: the first Right shows the frame on cell 1, the next moves it to cell 2; a held OK turns its sound on (AUDIO badge, toast), Menu turns it off; Left + Menu moves the sound to cell 1.
  • Android 5.0 emulator (API 21): the key handling (a held OK opens no menu, a short one opens it). Zoom on video could not be seen there: the emulator's software decoder failed on these streams ("Codec exception"); the decode path is not touched here.
  • Continuous key repeats of a physical remote held for seconds are generated by Android itself; they are not reproducible with input keyevent and remain for a check on a box with a real remote.

With the menu closed the remote now does what the gestures do:
- a held OK, or Menu, is the long press: a screenshot in the single view,
  the selected cell's sound on or off in multi-view; OK opens the menu on
  release, so that it can be held;
- single view: hold Up / Down to zoom in and out (down to 1x resets it),
  a short arrow pans the zoomed picture; zoom, channel and page keys and
  + / - zoom in steps of 1.25x, about the centre of the screen;
- multi-view: the arrows move a yellow selection frame over the cells
  (the first arrow shows it on the cell whose sound plays, or the first);
  it goes away after 4 s.

RemoteKeys holds the key mapping and the zoom, pan and grid arithmetic,
with unit tests. docs/usage.md and the three READMEs describe the keys.
Checked with D-pad input only on an Android TV 16 emulator (single view
and a 2x2 grid) and the key handling on Android 5.0.
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Add D-pad access to zoom, screenshots, and multi-view audio

✨ Enhancement 🧪 Tests 📝 Documentation ⚙️ Configuration changes 🕐 20-40 Minutes

Grey Divider

AI Description

• Enable remote zoom and pan in single view and cell selection in multi-view.
• Map held OK or Menu to existing long-press actions without reopening the menu.
• Add key-arithmetic tests, usage guidance, and the 2.20.0 release version.
Diagram

graph TD
  Input["Remote keys"] --> Gate{"Menu open?"} -->|No| Router["Decoder key routing"] --> Math["RemoteKeys helpers"] --> Video["Single view"]
  Router --> Grid["Grid selection"]
  Router --> Actions["Long actions"]
  Router -->|Short OK| Popup["Menu popup"]
  Gate -->|Yes| Popup
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Shared input-action layer
  • ➕ Could centralize gesture and remote commands as more input methods are added.
  • ➖ Requires a broader refactor of established touch handling for this focused feature.

Recommendation: Keep the scoped key router and pure RemoteKeys calculations: they reuse existing screenshot, audio, and video-transform behavior without disturbing touch input. Consider a shared action layer only if further input methods make the routing diverge.

Files changed (9) +452 / -39

Enhancement (2) +290 / -3
Decoder.javaRoute remote keys to view actions and grid selection +190/-3

Route remote keys to view actions and grid selection

• Opens the menu on short OK release while tracking held OK for screenshots or cell-audio toggling; Menu provides the same long action. Adds bounded single-view zoom and pan plus a temporary selection frame for multi-view cells.

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

RemoteKeys.javaAdd testable remote key and navigation calculations +100/-0

Add testable remote key and navigation calculations

• Defines zoom-key mappings, zoom and pan steps, centre-preserving pan calculations, and grid movement constrained to cell boundaries.

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

Tests (1) +111 / -0
RemoteKeysTest.javaTest remote mappings, zoom, pan, and grid movement +111/-0

Test remote mappings, zoom, pan, and grid movement

• Covers key directions, zoom limits and hold steps, pan arithmetic, reachable cells, and grid-edge behavior.

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

Documentation (5) +49 / -34
CHANGELOG.mdRecord the 2.20.0 remote-control feature +9/-0

Record the 2.20.0 remote-control feature

• Adds release notes for D-pad zoom, pan, grid selection, long-press actions, and OK-on-release menu behavior.

CHANGELOG.md

README.mdSummarize remote gestures in the English README +8/-8

Summarize remote gestures in the English README

• Expands the input table to mention held Up/Down, arrow panning, held OK, and remote cell selection.

README.md

README.ru.mdDescribe remote actions in the Russian README +8/-8

Describe remote actions in the Russian README

• Updates the translated input table with remote zoom, pan, held OK, and multi-view selection.

README.ru.md

README.zh-CN.mdDescribe remote actions in the Chinese README +8/-8

Describe remote actions in the Chinese README

• Updates the translated input table with remote zoom, pan, held OK, and multi-view selection.

README.zh-CN.md

usage.mdDocument closed-menu remote controls +16/-10

Document closed-menu remote controls

• Explains zoom, pan, grid selection, held OK and Menu actions, and OK-on-release behavior. Updates the multi-view audio and screenshot instructions.

docs/usage.md

Other (1) +2 / -2
build.gradleBump the app version to 2.20.0 +2/-2

Bump the app version to 2.20.0

• Increases versionCode from 49 to 50 and versionName from 2.19.1 to 2.20.0.

android/app/build.gradle

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

qodo-free-for-open-source-projects Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. The first arrow highlights the wrong cell ✓ Resolved
Description
onArrowDown() calls ensureQuadSelected() when the frame is hidden, but that method retains any
valid earlier selection instead of using the current audio cell. If the frame times out and a touch
long-press changes the audio to another cell, the next arrow highlights the old cell and subsequent
arrows move from it.
Code

android/app/src/main/java/com/openipc/decoder/Decoder.java[R2876-2878]

+            if (shown) quadSelected = RemoteKeys.moveCell(quadSelected, size, keyCode);
+            else ensureQuadSelected();
+            showQuadSelection(true);
Evidence
The touch handler changes audio without updating the remote selection; the timeout hides the frame
without clearing that selection. The new first-arrow branch then preserves the still-valid old
index.

android/app/src/main/java/com/openipc/decoder/Decoder.java[973-980]
android/app/src/main/java/com/openipc/decoder/Decoder.java[1090-1098]
android/app/src/main/java/com/openipc/decoder/Decoder.java[2873-2878]
android/app/src/main/java/com/openipc/decoder/Decoder.java[2899-2921]

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

## Issue description
After a frame times out, a touch long-press can change the audio cell while the stored remote selection remains on an older cell. The next first arrow highlights that older cell.
## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/Decoder.java[2873-2878]
- android/app/src/main/java/com/openipc/decoder/Decoder.java[2899-2905]
## Recommended Fix
When beginning a new visible arrow-selection sequence, derive its starting cell from the current audio cell or the first cell rather than retaining a stale selection. Preserve the intended behavior of a long OK on a cell selected by the remote.

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


2. The remote reports sound for empty cells ✓ Resolved
Description
remoteLongAction() sends every selected non-U grid index to toggleQuadAudio(), even when that
slot has no camera cell. In a grid with an unconfigured slot, holding OK or pressing Menu on it
saves that index and shows an audio-enabled toast, but no audio route is attached.
Code

android/app/src/main/java/com/openipc/decoder/Decoder.java[R2893-2895]

+            } else {
+                toggleQuadAudio(quadSelected);
+            }
Evidence
Grid construction provides a view for each slot, while camera-cell creation skips unconfigured URLs.
The new remote action accepts the view's index; toggling persists and announces it, whereas routing
requires a non-null camera cell.

android/app/src/main/java/com/openipc/decoder/Decoder.java[956-967]
android/app/src/main/java/com/openipc/decoder/Decoder.java[1047-1057]
android/app/src/main/java/com/openipc/decoder/Decoder.java[1090-1109]
android/app/src/main/java/com/openipc/decoder/Decoder.java[2884-2905]

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 new remote audio action accepts visible but unconfigured grid slots and reports that their audio is on, although no camera cell exists to provide it.
## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/Decoder.java[2884-2896]
- android/app/src/main/java/com/openipc/decoder/Decoder.java[1047-1058]
## Recommended Fix
Before toggling audio from the remote action, check that the selected camera slot has a configured audio-capable cell. Leave its selection frame usable, but do not persist an audio index or show an audio-enabled toast for an empty slot.

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


3. Some grid selections remain invisible ✓ Resolved
Description
buildQuadGrid() adds the selection frame before the startup overlay, and showQuadSelection()
changes its visibility without bringing it above that overlay. Empty camera slots never receive a
first frame, and the U cell may wait indefinitely for a stream, so remote users cannot see which of
those cells is selected.
Code

android/app/src/main/java/com/openipc/decoder/Decoder.java[R1011-1014]

+                cell.addView(frame, new FrameLayout.LayoutParams(
+                        FrameLayout.LayoutParams.MATCH_PARENT,
+                        FrameLayout.LayoutParams.MATCH_PARENT));
+                quadSelectFrames[idx] = frame;
Evidence
The new frame is added before overlays are created and brought to the front. A missing camera
configuration creates no cell whose first-frame callback could remove that overlay; showing the
frame does not change their stacking order.

android/app/src/main/java/com/openipc/decoder/Decoder.java[1004-1014]
android/app/src/main/java/com/openipc/decoder/Decoder.java[1070-1080]
android/app/src/main/java/com/openipc/decoder/Decoder.java[1167-1190]
android/app/src/main/java/com/openipc/decoder/Decoder.java[2902-2910]

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 remote selection frame sits beneath the startup overlay on cells that have not produced a frame, leaving empty slots and the waiting U cell without a visible selection indicator.
## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/Decoder.java[1004-1014]
- android/app/src/main/java/com/openipc/decoder/Decoder.java[2903-2910]
## Recommended Fix
When showing a selection, bring its frame above the startup overlay while preserving the visibility of cell hints and stats. Check the result on an empty camera slot and a U cell awaiting a stream.

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


View review recommended (1)
4. Canceled arrow presses still pan video ✓ Resolved
Description
onKeyUp() treats an Up or Down release as a short press whenever arrowRepeated is false, without
checking event.isCanceled(). If a zoomed single view receives a canceled release before any
repeat, that release changes the picture position even though the press was canceled.
Code

android/app/src/main/java/com/openipc/decoder/Decoder.java[R2829-2832]

+                if (isSingleView() && !menuManager.isPopupShowing()) {
+                    if (!arrowRepeated) panBy(keyCode);
+                    arrowRepeated = false;
+                    return true;
Evidence
The newly added release branch calls panBy() without a cancellation check, whereas the OK release
explicitly checks cancellation. panBy() updates both pan state and the rendered transform when
zoomed.

android/app/src/main/java/com/openipc/decoder/Decoder.java[2818-2834]
android/app/src/main/java/com/openipc/decoder/Decoder.java[2927-2935]

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

## Issue description
A canceled Up or Down release can execute the short-press pan action in a zoomed single view.
## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/Decoder.java[2826-2834]
## Recommended Fix
Check `event.isCanceled()` before panning on release, while still clearing `arrowRepeated` so the next arrow press starts with clean state.

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


Grey Divider

Context sources
❌ Tickets: failed to load — Ticket collection could not establish complete evidence
Review mode: Auto: ⚖️ Balanced: Downgraded extended -> standard: change is below the extended eligibility bar (hunks 17/18, lines 511/200; both must reach the floor). Router rationale: D-pad handling spans zoom, gestures, screenshots, and grid selection paths.

Grey Divider

Tip of the day
💡 Did you know, you can copy the agent prompt from any finding and feed it to your IDE agent

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Previous reviews

Review updated until commit c6719a0 ⚖️ Balanced

Results up to commit 2d57ead


🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (0) 📜 Skill insights (0)


Remediation recommended
1. The first arrow highlights the wrong cell 🐞 Bug ≡ Correctness ⭐ New
Description
onArrowDown() calls ensureQuadSelected() when the frame is hidden, but that method retains any
valid earlier selection instead of using the current audio cell. If the frame times out and a touch
long-press changes the audio to another cell, the next arrow highlights the old cell and subsequent
arrows move from it.
Code

android/app/src/main/java/com/openipc/decoder/Decoder.java[R2876-2878]

+            if (shown) quadSelected = RemoteKeys.moveCell(quadSelected, size, keyCode);
+            else ensureQuadSelected();
+            showQuadSelection(true);
Evidence
The touch handler changes audio without updating the remote selection; the timeout hides the frame
without clearing that selection. The new first-arrow branch then preserves the still-valid old
index.

android/app/src/main/java/com/openipc/decoder/Decoder.java[973-980]
android/app/src/main/java/com/openipc/decoder/Decoder.java[1090-1098]
android/app/src/main/java/com/openipc/decoder/Decoder.java[2873-2878]
android/app/src/main/java/com/openipc/decoder/Decoder.java[2899-2921]

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

## Issue description
After a frame times out, a touch long-press can change the audio cell while the stored remote selection remains on an older cell. The next first arrow highlights that older cell.

## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/Decoder.java[2873-2878]
- android/app/src/main/java/com/openipc/decoder/Decoder.java[2899-2905]

## Recommended Fix
When beginning a new visible arrow-selection sequence, derive its starting cell from the current audio cell or the first cell rather than retaining a stale selection. Preserve the intended behavior of a long OK on a cell selected by the remote.

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


2. The remote reports sound for empty cells 🐞 Bug ≡ Correctness ⭐ New
Description
remoteLongAction() sends every selected non-U grid index to toggleQuadAudio(), even when that
slot has no camera cell. In a grid with an unconfigured slot, holding OK or pressing Menu on it
saves that index and shows an audio-enabled toast, but no audio route is attached.
Code

android/app/src/main/java/com/openipc/decoder/Decoder.java[R2893-2895]

+            } else {
+                toggleQuadAudio(quadSelected);
+            }
Evidence
Grid construction provides a view for each slot, while camera-cell creation skips unconfigured URLs.
The new remote action accepts the view's index; toggling persists and announces it, whereas routing
requires a non-null camera cell.

android/app/src/main/java/com/openipc/decoder/Decoder.java[956-967]
android/app/src/main/java/com/openipc/decoder/Decoder.java[1047-1057]
android/app/src/main/java/com/openipc/decoder/Decoder.java[1090-1109]
android/app/src/main/java/com/openipc/decoder/Decoder.java[2884-2905]

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 new remote audio action accepts visible but unconfigured grid slots and reports that their audio is on, although no camera cell exists to provide it.

## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/Decoder.java[2884-2896]
- android/app/src/main/java/com/openipc/decoder/Decoder.java[1047-1058]

## Recommended Fix
Before toggling audio from the remote action, check that the selected camera slot has a configured audio-capable cell. Leave its selection frame usable, but do not persist an audio index or show an audio-enabled toast for an empty slot.

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


3. Some grid selections remain invisible ✓ Resolved
Description
buildQuadGrid() adds the selection frame before the startup overlay, and showQuadSelection()
changes its visibility without bringing it above that overlay. Empty camera slots never receive a
first frame, and the U cell may wait indefinitely for a stream, so remote users cannot see which of
those cells is selected.
Code

android/app/src/main/java/com/openipc/decoder/Decoder.java[R1011-1014]

+                cell.addView(frame, new FrameLayout.LayoutParams(
+                        FrameLayout.LayoutParams.MATCH_PARENT,
+                        FrameLayout.LayoutParams.MATCH_PARENT));
+                quadSelectFrames[idx] = frame;
Evidence
The new frame is added before overlays are created and brought to the front. A missing camera
configuration creates no cell whose first-frame callback could remove that overlay; showing the
frame does not change their stacking order.

android/app/src/main/java/com/openipc/decoder/Decoder.java[1004-1014]
android/app/src/main/java/com/openipc/decoder/Decoder.java[1070-1080]
android/app/src/main/java/com/openipc/decoder/Decoder.java[1167-1190]
android/app/src/main/java/com/openipc/decoder/Decoder.java[2902-2910]

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 remote selection frame sits beneath the startup overlay on cells that have not produced a frame, leaving empty slots and the waiting U cell without a visible selection indicator.
## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/Decoder.java[1004-1014]
- android/app/src/main/java/com/openipc/decoder/Decoder.java[2903-2910]
## Recommended Fix
When showing a selection, bring its frame above the startup overlay while preserving the visibility of cell hints and stats. Check the result on an empty camera slot and a U cell awaiting a stream.

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


View review recommended (1)
4. Canceled arrow presses still pan video ✓ Resolved
Description
onKeyUp() treats an Up or Down release as a short press whenever arrowRepeated is false, without
checking event.isCanceled(). If a zoomed single view receives a canceled release before any
repeat, that release changes the picture position even though the press was canceled.
Code

android/app/src/main/java/com/openipc/decoder/Decoder.java[R2829-2832]

+                if (isSingleView() && !menuManager.isPopupShowing()) {
+                    if (!arrowRepeated) panBy(keyCode);
+                    arrowRepeated = false;
+                    return true;
Evidence
The newly added release branch calls panBy() without a cancellation check, whereas the OK release
explicitly checks cancellation. panBy() updates both pan state and the rendered transform when
zoomed.

android/app/src/main/java/com/openipc/decoder/Decoder.java[2818-2834]
android/app/src/main/java/com/openipc/decoder/Decoder.java[2927-2935]

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

## Issue description
A canceled Up or Down release can execute the short-press pan action in a zoomed single view.
## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/Decoder.java[2826-2834]
## Recommended Fix
Check `event.isCanceled()` before panning on release, while still clearing `arrowRepeated` so the next arrow press starts with clean state.

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


Context sources
❌ Tickets: failed to load — Ticket collection could not establish complete evidence
Review mode: Auto: ⚖️ Balanced: Downgraded extended -> standard: change is below the extended eligibility bar (hunks 16/18, lines 502/200; both must reach the floor). Router rationale: Substantial input-state, zoom, and grid logic has multiple independent defect risks.
Results up to commit c26af35


🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (0) 📜 Skill insights (0)


Remediation recommended
1. Some grid selections remain invisible 🐞 Bug ≡ Correctness
Description
buildQuadGrid() adds the selection frame before the startup overlay, and showQuadSelection()
changes its visibility without bringing it above that overlay. Empty camera slots never receive a
first frame, and the U cell may wait indefinitely for a stream, so remote users cannot see which of
those cells is selected.
Code

android/app/src/main/java/com/openipc/decoder/Decoder.java[R1011-1014]

+                cell.addView(frame, new FrameLayout.LayoutParams(
+                        FrameLayout.LayoutParams.MATCH_PARENT,
+                        FrameLayout.LayoutParams.MATCH_PARENT));
+                quadSelectFrames[idx] = frame;
Evidence
The new frame is added before overlays are created and brought to the front. A missing camera
configuration creates no cell whose first-frame callback could remove that overlay; showing the
frame does not change their stacking order.

android/app/src/main/java/com/openipc/decoder/Decoder.java[1004-1014]
android/app/src/main/java/com/openipc/decoder/Decoder.java[1070-1080]
android/app/src/main/java/com/openipc/decoder/Decoder.java[1167-1190]
android/app/src/main/java/com/openipc/decoder/Decoder.java[2902-2910]

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 remote selection frame sits beneath the startup overlay on cells that have not produced a frame, leaving empty slots and the waiting U cell without a visible selection indicator.
## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/Decoder.java[1004-1014]
- android/app/src/main/java/com/openipc/decoder/Decoder.java[2903-2910]
## Recommended Fix
When showing a selection, bring its frame above the startup overlay while preserving the visibility of cell hints and stats. Check the result on an empty camera slot and a U cell awaiting a stream.

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


2. Canceled arrow presses still pan video 🐞 Bug ≡ Correctness
Description
onKeyUp() treats an Up or Down release as a short press whenever arrowRepeated is false, without
checking event.isCanceled(). If a zoomed single view receives a canceled release before any
repeat, that release changes the picture position even though the press was canceled.
Code

android/app/src/main/java/com/openipc/decoder/Decoder.java[R2829-2832]

+                if (isSingleView() && !menuManager.isPopupShowing()) {
+                    if (!arrowRepeated) panBy(keyCode);
+                    arrowRepeated = false;
+                    return true;
Evidence
The newly added release branch calls panBy() without a cancellation check, whereas the OK release
explicitly checks cancellation. panBy() updates both pan state and the rendered transform when
zoomed.

android/app/src/main/java/com/openipc/decoder/Decoder.java[2818-2834]
android/app/src/main/java/com/openipc/decoder/Decoder.java[2927-2935]

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

## Issue description
A canceled Up or Down release can execute the short-press pan action in a zoomed single view.
## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/Decoder.java[2826-2834]
## Recommended Fix
Check `event.isCanceled()` before panning on release, while still clearing `arrowRepeated` so the next arrow press starts with clean state.

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


Context sources
❌ Tickets: failed to load — Ticket collection could not establish complete evidence
Review mode: Auto: ⚖️ Balanced: Downgraded extended -> standard: change is below the extended eligibility bar (hunks 16/18, lines 491/200; both must reach the floor). Router rationale: Substantial input-state logic spans zoom, panning, menus, screenshots, and grids.

Grey Divider

Qodo Logo

@compot-dev

Copy link
Copy Markdown
Collaborator Author

Both findings fixed in 2d57ead:

  1. Selection frame under a cell's hint — showQuadSelection() now brings the selected cell's frame to the front of its cell. The frame has no fill, so the hint, the AUDIO badge and the stats stay readable. Checked on the Android TV 16 emulator: in a 2×2 grid with two slots configured, Down twice from cell 1 shows the frame on the empty cell 3 (before the fix it was hidden by the cell's hint).
  2. Cancelled Up / Down release panned — the release pans only for a press that went down in the single view (arrowDown), was not held (arrowRepeated) and is not cancelled (event.isCanceled()).

Local build in Docker as in CI: testDebugUnitTest, lintDebug (no new findings), assembleRelease.

@compot-dev

Copy link
Copy Markdown
Collaborator Author

/review

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

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 2d57ead

@compot-dev

Copy link
Copy Markdown
Collaborator Author

Both new findings fixed in c6719a0:

  1. The first arrow highlights the wrong cell — a long press on a cell (touch) now makes it the remote's selection too, so the next arrow starts from the cell touched last rather than an older one. A cell chosen with the arrows stays selected after its frame goes away, so a later held OK still acts on it; docs/usage.md says so.
  2. Sound for empty cells — a held OK / Menu on a slot without a camera cell now only says Camera N is not configured; it stores no audio index. A stored index on such a slot (from before) can still be turned off.

Local build in Docker as in CI: testDebugUnitTest, lintDebug (no new findings), assembleRelease. Not rerun on the emulator: both are small changes to the two branches above.

@compot-dev

Copy link
Copy Markdown
Collaborator Author

/review

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

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit c6719a0

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.

Remote control: zoom, reset zoom, screenshot and per-cell sound are touch-only

1 participant