Add close button to info card for classic 3-button nav users#932
Conversation
|
@gemini-code-assist review |
There was a problem hiding this comment.
Code Review
This pull request introduces several changes, including adding an explicit close button to the object info dialog for users on classic 2/3-button navigation, implementing a 15-second startup grace period in SensorAccuracyMonitor before displaying compass accuracy warnings, updating dependencies, and adding troubleshooting documentation. The reviewer feedback suggests wrapping the system settings read in NavigationModeUtil with a try-catch block to prevent potential SecurityException crashes on custom ROMs, and using monotonic SystemClock.elapsedRealtime() instead of System.currentTimeMillis() to robustly measure the startup grace period.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| fun isGestureNavigationEnabled(context: Context): Boolean { | ||
| return Settings.Secure.getInt(context.contentResolver, "navigation_mode", 0) == 2 | ||
| } |
There was a problem hiding this comment.
Reading system settings from Settings.Secure can occasionally throw a SecurityException or other runtime exceptions on highly customized Android ROMs, restricted user profiles (e.g., guest mode, work profiles), or in certain testing environments. Wrapping this in a try-catch block and falling back to false (classic navigation) is a safer, defensive approach. Falling back to false is safe because it will simply show the close button, which is harmless, whereas a crash would be critical.
fun isGestureNavigationEnabled(context: Context): Boolean {
return try {
Settings.Secure.getInt(context.contentResolver, "navigation_mode", 0) == 2
} catch (e: Exception) {
false
}
}| private val toaster: Toaster | ||
| private var started = false | ||
| private var hasReading = false | ||
| private var startedAtMillis = 0L |
There was a problem hiding this comment.
Using System.currentTimeMillis() to measure elapsed time intervals can lead to bugs if the system clock is adjusted (e.g., via network time synchronization or manual user changes) during the grace period. Using SystemClock.elapsedRealtime() is monotonic and guaranteed to be unaffected by clock adjustments, making it the standard and robust choice for measuring intervals in Android.
Let's update startedAtMillis to use elapsed realtime.
| private var startedAtMillis = 0L | |
| private var startedAtElapsedMillis = 0L |
| return | ||
| } | ||
| Log.d(TAG, "Starting monitoring compass accuracy") | ||
| startedAtMillis = System.currentTimeMillis() |
| val nowMillis = System.currentTimeMillis() | ||
| if (nowMillis - startedAtMillis < STARTUP_GRACE_PERIOD_MILLIS) { | ||
| Log.d(TAG, "...but still within startup grace period, letting the user settle in first") | ||
| return | ||
| } |
There was a problem hiding this comment.
Perform the startup grace period check using monotonic elapsed realtime, while keeping the wall-clock time for the persisted warning interval check.
| val nowMillis = System.currentTimeMillis() | |
| if (nowMillis - startedAtMillis < STARTUP_GRACE_PERIOD_MILLIS) { | |
| Log.d(TAG, "...but still within startup grace period, letting the user settle in first") | |
| return | |
| } | |
| val nowElapsedMillis = android.os.SystemClock.elapsedRealtime() | |
| if (nowElapsedMillis - startedAtElapsedMillis < STARTUP_GRACE_PERIOD_MILLIS) { | |
| Log.d(TAG, "...but still within startup grace period, letting the user settle in first") | |
| return | |
| } | |
| val nowMillis = System.currentTimeMillis() |
There was a problem hiding this comment.
Code Review
This pull request introduces several updates, including a startup grace period for the compass accuracy monitor to prevent premature warnings, an explicit close button on the object info dialog for users not using gesture navigation, and corresponding troubleshooting documentation updates. Feedback on the code changes suggests using monotonic SystemClock.elapsedRealtime() instead of System.currentTimeMillis() for measuring the grace period, always showing the dismiss button on the info dialog to avoid relying on undocumented settings, and updating the troubleshooting guides to mention the new close button.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| private val toaster: Toaster | ||
| private var started = false | ||
| private var hasReading = false | ||
| private var startedAtMillis = 0L |
| return | ||
| } | ||
| Log.d(TAG, "Starting monitoring compass accuracy") | ||
| startedAtMillis = System.currentTimeMillis() |
There was a problem hiding this comment.
Using System.currentTimeMillis() to measure elapsed time (such as the startup grace period) is susceptible to issues if the system clock is adjusted (e.g., via network time sync or manual user changes). For monotonic elapsed time measurements, it is highly recommended to use SystemClock.elapsedRealtime() instead.
| startedAtMillis = System.currentTimeMillis() | |
| startedAtElapsedRealtime = android.os.SystemClock.elapsedRealtime() |
| if (nowMillis - startedAtMillis < STARTUP_GRACE_PERIOD_MILLIS) { | ||
| Log.d(TAG, "...but still within startup grace period, letting the user settle in first") | ||
| return | ||
| } |
There was a problem hiding this comment.
Use the monotonic SystemClock.elapsedRealtime() to check if the startup grace period has elapsed.
| if (nowMillis - startedAtMillis < STARTUP_GRACE_PERIOD_MILLIS) { | |
| Log.d(TAG, "...but still within startup grace period, letting the user settle in first") | |
| return | |
| } | |
| if (android.os.SystemClock.elapsedRealtime() - startedAtElapsedRealtime < STARTUP_GRACE_PERIOD_MILLIS) { | |
| Log.d(TAG, "...but still within startup grace period, letting the user settle in first") | |
| return | |
| } |
| // Users on classic 2/3-button navigation have no visible Back button to dismiss the | ||
| // card with, since the app runs full screen. Give them an explicit close button. | ||
| if (!NavigationModeUtil.isGestureNavigationEnabled(parentActivity)) { | ||
| builder.setNegativeButton(android.R.string.ok) { dialog, _ -> dialog.dismiss() } | ||
| } |
There was a problem hiding this comment.
Relying on the undocumented "navigation_mode" setting in Settings.Secure is fragile, as it is an internal API that is not guaranteed to be present or behave consistently across all Android OEMs and custom ROMs.
Additionally, even for gesture-navigation users, performing a back gesture in a full-screen interactive app like Sky Map can be finicky (as it can conflict with map dragging gestures or require an extra swipe to reveal the gesture area).
Recommendation:
Consider always showing a dismiss button (using android.R.string.cancel or a "Close" resource) for all users, regardless of their navigation mode. This simplifies the codebase by eliminating the need for NavigationModeUtil entirely and provides a consistent, reliable, and intuitive way to dismiss the dialog for all users.
| // Users on classic 2/3-button navigation have no visible Back button to dismiss the | |
| // card with, since the app runs full screen. Give them an explicit close button. | |
| if (!NavigationModeUtil.isGestureNavigationEnabled(parentActivity)) { | |
| builder.setNegativeButton(android.R.string.ok) { dialog, _ -> dialog.dismiss() } | |
| } | |
| builder.setNegativeButton(android.R.string.cancel) { dialog, _ -> dialog.dismiss() } |
| If you're using the older "classic" 3-button Android navigation (rather than gesture navigation), | ||
| Sky Map runs full screen, so the on-screen Back/Home/Recents buttons aren't rendered at all. Swipe | ||
| up from the very bottom of the screen to bring the navigation bar into view, then tap Back to | ||
| close the card. |
There was a problem hiding this comment.
Since this PR introduces an explicit close button on the info card for classic 3-button navigation users, they no longer have to swipe up to reveal the navigation bar to close the card. The troubleshooting text should be updated to reflect this new capability.
| If you're using the older "classic" 3-button Android navigation (rather than gesture navigation), | |
| Sky Map runs full screen, so the on-screen Back/Home/Recents buttons aren't rendered at all. Swipe | |
| up from the very bottom of the screen to bring the navigation bar into view, then tap Back to | |
| close the card. | |
| If you're using the older "classic" 3-button Android navigation (rather than gesture navigation), | |
| an explicit close button is provided on the card. Alternatively, you can swipe up from the very | |
| bottom of the screen to bring the navigation bar into view, then tap Back. |
| 3. If using classic 3-button navigation, swipe up from the very bottom of the screen to bring the | ||
| navigation bar into view, then tap Back |
There was a problem hiding this comment.
Update the suggested steps for LLM responses to mention the new close button on the card for classic 3-button navigation users.
| 3. If using classic 3-button navigation, swipe up from the very bottom of the screen to bring the | |
| navigation bar into view, then tap Back | |
| 3. If using classic 3-button navigation, tap the close button on the card, or swipe up from the | |
| very bottom of the screen to bring the navigation bar into view and tap Back |
Sky Map runs full screen, so users on classic 2/3-button on-screen navigation have no visible Back button to dismiss the info card and must swipe up to reveal the nav bar. Detect classic nav via the navigation_mode system setting and add an explicit close button in that case only; gesture-nav users see no change. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ece45ef to
8744096
Compare
Settings.Secure reads can throw on restricted profiles or customized ROMs; fall back to classic-nav (false) on failure since that's the safe direction (an extra harmless button, not a crash).
|
@gemini-code-assist review |
There was a problem hiding this comment.
Code Review
This pull request introduces a new utility, NavigationModeUtil, to detect whether the device is using gesture or classic 2/3-button navigation. In ObjectInfoDialogFragment, this utility is used to conditionally add an explicit close button for users on classic navigation, ensuring they can dismiss the dialog when running in full screen. There are no review comments, so I have no feedback to provide.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
Summary
NavigationModeUtil.isGestureNavigationEnabled(), which reads thenavigation_modesystem setting to detect classic vs. gesture navigation.ObjectInfoDialogFragmentnow adds a negative "OK" button to the info card'sAlertDialogonly when classic navigation is detected. Gesture-nav users see no change.Test plan
./gradlew :app:compileGmsDebugKotlinpasses🤖 Generated with Claude Code