Skip to content

feat: Reset in the menu, menu in two columns (#171, #173) - #172

Merged
compot-dev merged 6 commits into
v2from
feat/factory-reset-171
Oct 14, 2026
Merged

compot-dev merged 6 commits into
v2from
feat/factory-reset-171

Conversation

@compot-dev

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

Copy link
Copy Markdown
Collaborator

Reset clears all settings after a confirmation (#171). The menu now has two items per row (#173):

[ 1 2 3 4 5 6 7 8 U D Q S ]
[ Settings      | WebUI   ]   (single view only)
[ Exit [v…, …]  | Reset   ]

Reset opens:

Start with a clean slate?
This clears all camera slots, their transports and the other settings, so you can set the app up again from scratch. The app restarts and opens as right after installing. Your cameras are not changed.
[Clear settings] [Cancel]

Cancel has the focus, so a stray OK on a remote changes nothing (checked on AG-216 with the D-pad).

Clear settings:

  • clears the settings preferences with commit(); if that fails, it stops there with a message and changes nothing else;
  • stops every stream;
  • deletes the Android Keystore key of the encrypted camera URLs;
  • clears WebUI's HTTP logins and cookies, and goes on once the cookie removal has finished;
  • starts the app again in a new process.

Qodo on c6b5600:

  1. commit() result ignored: fixed.
  2. Key deletion failure: logged and the reset goes on. The URLs it encrypted are already gone with the preferences, and the next save reuses the key.
  3. Restart: checked on Android 15 (TECNO KM4): the app reopened in a new process. The exit now waits 300 ms after the launch.
  4. Cookies: the removal callback comes before the restart. Fixed.
  5. HTTP auth logins: now cleared. Fixed.

README (EN/RU/ZH): Reset in the menu table. Version 2.05.

Closes #171
Closes #173

Reset (above Exit) asks first; Cancel has the focus, so a stray OK on a
remote changes nothing. Reset deletes the stored settings, the Keystore
key of the encrypted camera URLs and WebUI's cookies, then starts the
app in a new process.
@compot-dev compot-dev changed the title feat: Reset to factory settings from the menu (#171) feat: Start over — clear all settings from the menu (#171) Oct 14, 2026
@compot-dev
compot-dev force-pushed the feat/factory-reset-171 branch from 6ba93c6 to c6b5600 Compare October 14, 2026 19:08
@compot-dev

Copy link
Copy Markdown
Collaborator Author

/review

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

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

Copy link
Copy Markdown

Code Review by Qodo

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

Grey Divider


Action required

1. Reset can leave saved settings behind ✓ Resolved
Description
onStartOver() ignores the boolean result of commit() and proceeds to delete the URL encryption
key and restart the app. If the preference write fails, the old settings remain instead of restoring
first-start state; plaintext URLs remain readable and encrypted URLs remain stored.
Code

android/app/src/main/java/com/openipc/decoder/Decoder.java[494]

+        getSharedPreferences("settings", MODE_PRIVATE).edit().clear().commit();
Evidence
The reset requirement calls for clearing every stored setting and returning the app to first-install
state, but the preference clear only takes effect if commit() succeeds. The reset ignores that
result and continues to key deletion; the credential store also permits plaintext URL storage and
returns those stored values unchanged.

Clear stored settings and camera URL encryption key
android/app/src/main/java/com/openipc/decoder/Decoder.java[494-494]
android/app/src/main/java/com/openipc/decoder/Decoder.java[493-500]
android/app/src/main/java/com/openipc/decoder/CredentialStore.java[29-34]
android/app/src/main/java/com/openipc/decoder/CredentialStore.java[46-60]

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 failed settings commit can leave camera configuration and other preferences on disk while reset continues to delete the URL encryption key and restart the app.
## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/Decoder.java[493-500]
## Recommended Fix
Check the boolean returned by `commit()`. If it is false, stop the reset before key deletion or restart, surface an error, and leave the current process intact so the user can retry.

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


2. Reset can retain the URL encryption key 📎 Requirement gap ⛨ Security
Description
onStartOver() catches every exception from KeystoreCipher.deleteKey() and continues with the
restart. If the keystore operation fails, the camera URL encryption key remains while the app still
proceeds as though the reset completed.
Code

android/app/src/main/java/com/openipc/decoder/Decoder.java[R495-500]

+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            try {
+                KeystoreCipher.deleteKey();
+            } catch (Exception e) {
+                Log.w(TAG, "Start over: cannot delete the URL key: " + e.getMessage());
+            }
Evidence
The reset requirement explicitly requires removal of the camera URL encryption Keystore key. The
changed exception handler suppresses deletion failures and allows the reset flow to continue,
leaving the key present whenever deleteKey() throws.

Clear stored settings and camera URL encryption key
android/app/src/main/java/com/openipc/decoder/Decoder.java[495-500]

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 reset path logs a failed camera URL key deletion and continues, so the required encryption key can remain after the app restarts.
## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/Decoder.java[495-500]
## Recommended Fix
Treat key deletion failure as a failed reset: report the error to the user, do not launch or terminate the replacement process, and allow the user to retry after the keystore operation succeeds.

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


3. The app can close instead of restarting ✓ Resolved
Description
onStartOver() starts the replacement activity and then immediately calls
Runtime.getRuntime().exit(0), without a handoff to another process. Because Decoder runs in the
process being exited, the new activity may be killed before it opens and loads the cleared settings.
Code

android/app/src/main/java/com/openipc/decoder/Decoder.java[R511-513]

+        startActivity(restart);
+        finishAndRemoveTask();
+        Runtime.getRuntime().exit(0);
Evidence
The added sequence starts an activity and immediately exits; the manifest assigns no separate
process to that activity. Its settings-loading and stream startup occur in lifecycle callbacks that
the exit can preempt.

android/app/src/main/java/com/openipc/decoder/Decoder.java[508-513]
android/app/src/main/AndroidManifest.xml[21-32]
android/app/src/main/java/com/openipc/decoder/Decoder.java[2113-2135]

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 replacement activity is launched in the same process that reset immediately terminates, so reopening is not guaranteed.
## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/Decoder.java[508-513]
- android/app/src/main/AndroidManifest.xml[21-32]
## Recommended Fix
Arrange the relaunch through a mechanism that survives termination of the current process, then end the current activity and process without removing the replacement launch.

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



Remediation recommended

4. WebUI cookies can survive reset ✓ Resolved
Description
onStartOver() calls asynchronous removeAllCookies(null) and immediately flushes cookies without
waiting for removal to finish. When the process exits moments later, the pending deletion may not
reach persistent WebView storage.
Code

android/app/src/main/java/com/openipc/decoder/Decoder.java[R503-504]

+            android.webkit.CookieManager.getInstance().removeAllCookies(null);
+            android.webkit.CookieManager.getInstance().flush();
Evidence
The added code supplies no deletion callback and exits immediately after the flush. The app opens a
WebView for camera WebUI, so that cookie store can contain session state.

android/app/src/main/java/com/openipc/decoder/Decoder.java[502-513]
android/app/src/main/java/com/openipc/decoder/MenuManager.java[552-576]

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

## Issue description
Cookie removal has no completion callback, but reset flushes storage and exits immediately.
## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/Decoder.java[502-513]
## Recommended Fix
Supply a completion callback to `removeAllCookies`; flush cookies and proceed with the restart only after that callback runs.

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


5. WebUI login credentials can survive reset ✓ Resolved
Description
onStartOver() clears WebView cookies but does not clear its separate HTTP authentication
credential store. The WebUI passes camera credentials to HttpAuthHandler.proceed(), so credentials
cached through that path are outside the new cleanup.
Code

android/app/src/main/java/com/openipc/decoder/Decoder.java[R503-504]

+            android.webkit.CookieManager.getInstance().removeAllCookies(null);
+            android.webkit.CookieManager.getInstance().flush();
Evidence
The WebUI supplies URL-derived credentials to WebView's HTTP-auth handler. The added WebView cleanup
addresses cookies alone, not the HTTP-auth credential database.

android/app/src/main/java/com/openipc/decoder/MenuManager.java[567-576]
android/app/src/main/java/com/openipc/decoder/Decoder.java[502-507]

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

## Issue description
Reset deletes cookies but leaves WebView's separate HTTP authentication credentials untouched.
## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/Decoder.java[502-507]
- android/app/src/main/java/com/openipc/decoder/MenuManager.java[567-576]
## Recommended Fix
Clear WebView's stored HTTP authentication usernames and passwords as part of the confirmed reset, alongside cookie removal.

ⓘ 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 switch off images and animations for a plain-text comment

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread android/app/src/main/java/com/openipc/decoder/Decoder.java Outdated
Comment on lines +495 to +500
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
try {
KeystoreCipher.deleteKey();
} catch (Exception e) {
Log.w(TAG, "Start over: cannot delete the URL key: " + e.getMessage());
}

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. Reset can retain the url encryption key 📎 Requirement gap ⛨ Security

onStartOver() catches every exception from KeystoreCipher.deleteKey() and continues with the
restart. If the keystore operation fails, the camera URL encryption key remains while the app still
proceeds as though the reset completed.
Agent Prompt
## Issue description
The reset path logs a failed camera URL key deletion and continues, so the required encryption key can remain after the app restarts.

## Fix Focus Areas
- android/app/src/main/java/com/openipc/decoder/Decoder.java[495-500]

## Recommended Fix
Treat key deletion failure as a failed reset: report the error to the user, do not launch or terminate the replacement process, and allow the user to retry after the keystore operation succeeds.

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

Comment thread android/app/src/main/java/com/openipc/decoder/Decoder.java Outdated
Comment thread android/app/src/main/java/com/openipc/decoder/Decoder.java Outdated
Comment thread android/app/src/main/java/com/openipc/decoder/Decoder.java Outdated
… Reset checks the settings write, waits for the cookies and clears WebUI's HTTP logins (#171, #173, Qodo on #172)
@compot-dev
compot-dev force-pushed the feat/factory-reset-171 branch from c6b5600 to 2236afe Compare October 14, 2026 19:15
@compot-dev compot-dev changed the title feat: Start over — clear all settings from the menu (#171) feat: Reset in the menu, menu in two columns (#171, #173) Oct 14, 2026
…m a helper process, so the new launch is not ended with the old process (Qodo on #172)
@compot-dev
compot-dev force-pushed the feat/factory-reset-171 branch from 2236afe to 2d96037 Compare October 14, 2026 19:21
@compot-dev
compot-dev merged commit bda59ad into v2 Oct 14, 2026
4 checks passed
@compot-dev
compot-dev deleted the feat/factory-reset-171 branch October 14, 2026 19:29
compot-dev added a commit that referenced this pull request Oct 15, 2026
… Reset checks the settings write, waits for the cookies and clears WebUI's HTTP logins (#171, #173, Qodo on #172)
compot-dev added a commit that referenced this pull request Oct 15, 2026
…m a helper process, so the new launch is not ended with the old process (Qodo on #172)
compot-dev added a commit that referenced this pull request Oct 15, 2026
feat: Reset in the menu, menu in two columns (#171, #173)
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.

Menu: two items per row — [ Settings | WebUI ] and [ Exit + version | Reset ] Reset: clear all settings from the menu, with a confirmation

1 participant