Repository navigation
Conversation
🤖 Pull request artifacts
|
8c7f581 to
f541c0f
Compare
87c23d4 to
565a464
Compare
When explicit registration completes with a null FCM token, SSE starts as the fallback transport. The later FCM token update via RegistrationWorker set the token but never tore down the SSE stream, leaving both transports active and causing duplicate cloud-event delivery. Tear down SSE in updateDevice when a non-null push token is set. Fixes Greptile review blocker on PR #430.
…M token Symmetrize SSE management in EventsReceiver: when a DeviceRegisteredEvent is processed after the FCM token has been recorded, stop the SSE foreground service instead of leaving it running alongside FCM. Prevents duplicate cloud-event delivery reported by Greptile on PR #430.
Capture the application context up front and use nullable activity access for the progress bar so an in-flight explicit registration no longer throws from requireContext()/requireActivity() if the user navigates away, which would abort SSE startup and service.start() for an already-registered device. Addresses Greptile P1 'Fragment detachment aborts SSE startup' on PR #430.
78258ec to
60d3114
Compare
0c955cf to
ded47f7
Compare
f470387 to
4fd3ab9
Compare
f409d7b to
cde7b68
Compare
66ddd2b to
98643d2
Compare
98643d2 to
7b4ea1b
Compare
737b291 to
e91c1fd
Compare
|
This PR is stale because it has been open for 7 days with no activity. |
e91c1fd to
e6f3568
Compare
This comment has been minimized.
This comment has been minimized.
2a863f2 to
3de2a03
Compare
|
This PR is stale because it has been open for 7 days with no activity. |
3de2a03 to
f939ba7
Compare
| private fun refreshRegistrationUi() { | ||
| findPreference<Preference>("gateway.clear_password")?.isVisible = settings.hasPassword |
There was a problem hiding this comment.
Password control stays disabled
When this page opens without a registration, the password preference is disabled. After registration succeeds, refreshRegistrationUi() updates the related controls but never updates the password preference's isEnabled value. Users must leave and reopen the page before they can change their password. Set isEnabled from settings.username != null during this refresh.
| private fun refreshRegistrationUi() { | |
| findPreference<Preference>("gateway.clear_password")?.isVisible = settings.hasPassword | |
| private fun refreshRegistrationUi() { | |
| findPreference<EditTextPreference>("gateway.password")?.isEnabled = settings.username != null | |
| findPreference<Preference>("gateway.clear_password")?.isVisible = settings.hasPassword |
Prompt To Fix With AI
This is a comment left during a code review.
Path: app/src/main/java/me/capcom/smsgateway/ui/settings/CloudServerSettingsFragment.kt
Line: 313-314
Comment:
**Password control stays disabled**
When this page opens without a registration, the password preference is disabled. After registration succeeds, `refreshRegistrationUi()` updates the related controls but never updates the password preference's `isEnabled` value. Users must leave and reopen the page before they can change their password. Set `isEnabled` from `settings.username != null` during this refresh.
```suggestion
private fun refreshRegistrationUi() {
findPreference<EditTextPreference>("gateway.password")?.isEnabled = settings.username != null
findPreference<Preference>("gateway.clear_password")?.isVisible = settings.hasPassword
```
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.f939ba7 to
7f46a89
Compare
| settings.registrationInfo = null | ||
| // Stop SSE session and cloud workers so they do not keep using | ||
| // credentials of the just-unregistered device. | ||
| service.stop(requireContext()) |
There was a problem hiding this comment.
Unregister still accepts cloud commands
unregisterDevice() clears local credentials and stops the gateway, but leaves the server registration active. The server still sends commands to the device’s FCM token. PushService.onMessageReceived() routes them without checking registration, and the separate receiver for MessagesExportRequested remains running. The former cloud account can therefore still request SMS exports after unregister.
Remove or revoke the server registration, and reject commands from the old registration.
How this was verified: The server retains the push token, incoming FCM messages are routed without a registration check, and the separate export receiver remains active after the gateway stops.
Prompt To Fix With AI
This is a comment left during a code review.
Path: app/src/main/java/me/capcom/smsgateway/ui/settings/CloudServerSettingsFragment.kt
Line: 305-308
Comment:
**Unregister still accepts cloud commands**
`unregisterDevice()` clears local credentials and stops the gateway, but leaves the server registration active. The [server still sends commands to the device’s FCM token](https://github.com/android-sms-gateway/server/blob/HEAD/internal/sms-gateway/modules/events/service.go). `PushService.onMessageReceived()` routes them without checking registration, and the separate receiver for `MessagesExportRequested` remains running. The former cloud account can therefore still request SMS exports after unregister.
Remove or revoke the server registration, and reject commands from the old registration.
**How this was verified:** The server retains the push token, incoming FCM messages are routed without a registration check, and the separate export receiver remains active after the gateway stops.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| lifecycleScope.launch { | ||
| try { | ||
| gatewaySvc.registerDevice( | ||
| requireContext(), | ||
| null, | ||
| GatewayService.RegistrationMode.Anonymous | ||
| ) | ||
| requestPermissionsAndStart() |
There was a problem hiding this comment.
Signup requests overwrite each other
The new SignUp path leaves Start available while registerDevice() waits for the server. Tapping Start again opens another signup dialog because registrationInfo is still null. Confirming it launches another registration. Each anonymous request creates a separate account and device, and whichever response finishes last overwrites the saved credentials—even if an earlier signup already appeared successful.
Block repeated starts until registration finishes.
Prompt To Fix With AI
This is a comment left during a code review.
Path: app/src/main/java/me/capcom/smsgateway/ui/HomeFragment.kt
Line: 79-86
Comment:
**Signup requests overwrite each other**
The new `SignUp` path leaves Start available while `registerDevice()` waits for the server. Tapping Start again opens another signup dialog because `registrationInfo` is still null. Confirming it launches another registration. Each anonymous request creates a separate account and device, and whichever response finishes last overwrites the saved credentials—even if an earlier signup already appeared successful.
Block repeated starts until registration finishes.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| } catch (th: Throwable) { | ||
| Toast.makeText( | ||
| requireContext(), | ||
| "Failed to register device: ${th.message}", | ||
| Toast.LENGTH_LONG | ||
| ).show() |
There was a problem hiding this comment.
The new SignUp handler catches lifecycle cancellation as Throwable and calls requireContext() to show an error. If the activity is destroyed while registration waits for the network, the fragment can detach before this catch runs. requireContext() then throws outside the handler and crashes the app.
Rethrow CancellationException and avoid requiring an attached fragment after the network call.
Prompt To Fix With AI
This is a comment left during a code review.
Path: app/src/main/java/me/capcom/smsgateway/ui/HomeFragment.kt
Line: 87-92
Comment:
**Leaving signup can crash**
The new `SignUp` handler catches lifecycle cancellation as `Throwable` and calls `requireContext()` to show an error. If the activity is destroyed while registration waits for the network, the fragment can detach before this catch runs. `requireContext()` then throws outside the handler and crashes the app.
Rethrow `CancellationException` and avoid requiring an attached fragment after the network call.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
Summary
Adds explicit cloud register / unregister controls in cloud server settings and reworks the SSE/FCM lifecycle coordination so realtime delivery stays correct across registration, account replacement, and unregister.
Key changes:
GatewayService.registerDevicepersists the new identity, then emitsDeviceRegisteredEvent.Success; SSE credentials are resolved fresh on everySSEManager.connect(no cached stale token).isDisconnectingflag checked in every callback.RegistrationWorkeris narrowed to updating an existing device with the FCM token (background refresh only).CloudServerSettingsFragmentstops the gateway pipeline before registering, restores it after, and swallows non-fatal post-success UI errors.CancellationException).Why
Previously registration was implicit/automatic; users could not intentionally (re)register or unregister, and several lifecycle races could leave SSE bound to a stale account or drop the registration event for SSE-only devices.
Known limitation (deferred)
GatewayService.start()revives the workers and the events receiver but does not start SSE.DeviceRegisteredEvent.Successis emitted while the receiver is stopped, so it has no collector at that moment. SSE therefore resumes only indirectly, when the FCMRegistrationWorkerre-runsupdateDevice()and re-emits the event to the already-restarted receiver.This is left as-is for now. The interim workaround is the restart-app hint in
device_registered_successfully; the gap is recorded in a comment on theCancellationExceptionbranch ofregisterDeviceInternaland is being tracked separately. Explicitly startingSSEForegroundServiceon both the success and rollback paths would close it.Test plan
SSEManagerTest- not written yet. The concurrency rework inSSEManagercurrently has no unit coverage, and CI only builds an APK without running unit tests, so nothing guards this path today.Fix unregister’s remaining FCM command access and Home signup’s request and cancellation problems before merging.
Findings
Fix with agent prompt
Summary
Adds explicit cloud registration and unregister controls, moves background registration work to device updates, and changes SSE teardown and transport switching.
Diagram
%%{init: {'theme': 'neutral'}}%% flowchart TD A[User unregisters] --> B[Clear local credentials] B --> C[Stop gateway receiver and workers] C --> D[Server still holds FCM token] D --> E[PushService receives command] E --> F[EventsRouter] F --> G[Separate export receiver remains active] G --> H[ReceiverService exports SMS]Reviews (41) · Last reviewed commit: "[gateway] explicit registration, unregis..." · Reviewed by Greptile