ADFA-4051: Invisible symbol input view#1358
Conversation
📝 WalkthroughRelease NotesFeatures & Improvements:
Technical Changes:
WalkthroughThe PR refactors bottom sheet state management in the editor to respond intelligently to keyboard visibility. Constants are imported and applied consistently, keyboard inset handling accounts for both IME and system bars, and the sheet transitions between collapsed and hidden states based on whether the soft keyboard is visible during fullscreen mode. EditorBottomSheet's peek height logic is also simplified to depend only on search mode activation. ChangesKeyboard-Aware Bottom Sheet State Management
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@app/src/main/java/com/itsaky/androidide/activities/editor/FullscreenManager.kt`:
- Around line 231-232: FullscreenManager.applyFullscreen currently unsafely
casts contentBinding.root.context to Activity for
KeyboardUtils.isSoftInputVisible; instead unwrap the view context by walking
ContextWrapper (while ctx is ContextWrapper set ctx = ctx.baseContext) until you
find an Activity, or accept/pass the owning Activity into FullscreenManager and
use that; then call KeyboardUtils.isSoftInputVisible(activity). Reference:
FullscreenManager.applyFullscreen, contentBinding.root.context, and
KeyboardUtils.isSoftInputVisible; add android.content.ContextWrapper import if
unwrapping.
In `@app/src/main/java/com/itsaky/androidide/ui/EditorBottomSheet.kt`:
- Line 357: Replace the float-to-int conversion for the bottom sheet peek height
to use rounding instead of truncation: locate the assignment to
behavior.peekHeight in EditorBottomSheet (the line using isSearchModeActive and
collapsedHeight) and change the conversion of collapsedHeight to use
roundToInt() so it matches other uses in this file and avoids off-by-one pixel
errors.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 0f081816-93e2-4a58-a5e3-27481c74f805
📒 Files selected for processing (3)
app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.ktapp/src/main/java/com/itsaky/androidide/activities/editor/FullscreenManager.ktapp/src/main/java/com/itsaky/androidide/ui/EditorBottomSheet.kt
| val isKeyboardOpen = KeyboardUtils.isSoftInputVisible(contentBinding.root.context as Activity) | ||
| val targetState = if (isKeyboardOpen) BottomSheetBehavior.STATE_COLLAPSED else BottomSheetBehavior.STATE_HIDDEN |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Find how ContentEditorBinding / content root is inflated and what context backs it
rg -nP --type=kotlin -C3 '\bContentEditorBinding\b'
rg -nP --type=kotlin -C3 'isSoftInputVisible'Repository: appdevforall/CodeOnTheGo
Length of output: 9661
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Show surrounding code in FullscreenManager.kt
nl -ba app/src/main/java/com/itsaky/androidide/activities/editor/FullscreenManager.kt | sed -n '180,270p'
# 2) Find where FullscreenManager is instantiated
rg -n --type=kotlin "FullscreenManager\s*\(" app/src/main/java/com/itsaky/androidide | head -n 50
# 3) Inspect BaseEditorActivity binding initialization (where ActivityEditorBinding / content binding is inflated)
rg -n --type=kotlin "_binding\s*=\s*" app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt
nl -ba app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt | sed -n '150,280p'
# 4) Locate where ActivityEditorBinding.inflate is called (more precise)
rg -n --type=kotlin "ActivityEditorBinding\.inflate|inflate\(.*ActivityEditorBinding" app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt app/src/main/java/com/itsaky/androidide/activities/editor/*.ktRepository: appdevforall/CodeOnTheGo
Length of output: 111
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Surrounding code in FullscreenManager.kt (no nl; use cat -n)
sed -n '190,260p' app/src/main/java/com/itsaky/androidide/activities/editor/FullscreenManager.kt
echo "----"
cat -n app/src/main/java/com/itsaky/androidide/activities/editor/FullscreenManager.kt | sed -n '210,245p'
# 2) Find FullscreenManager instantiation call sites
rg -n --type=kotlin "FullscreenManager\s*\(" app/src/main/java/com/itsaky/androidide | head -n 50
# 3) Inspect BaseEditorActivity binding initialization area
cat -n app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt | sed -n '120,260p'
# 4) Look specifically for ActivityEditorBinding.inflate / setContentView usage
rg -n --type=kotlin "ActivityEditorBinding\.(inflate|bind)\(|inflate\(.*ActivityEditorBinding|setContentView\(.*ActivityEditorBinding" app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.ktRepository: appdevforall/CodeOnTheGo
Length of output: 10983
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# BaseEditorActivity: binding inflate region and where fullscreenManager is created
sed -n '480,560p' app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt
echo "----"
sed -n '620,720p' app/src/main/java/com/itsaky/androidide/activities/editor/BaseEditorActivity.kt
# KeyboardUtils: locate and show isSoftInputVisible implementation/signature
rg -n --type=kotlin "object\s+KeyboardUtils|class\s+KeyboardUtils|fun\s+isSoftInputVisible" app/src/main/java/com/itsaky/androidide | head -n 50Repository: appdevforall/CodeOnTheGo
Length of output: 5010
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Find KeyboardUtils source file
rg -n --type=kotlin "isSoftInputVisible\s*\(" app/src/main/java/com/itsaky/androidide | head -n 50
# 2) Show definition region (try common file locations by name)
fd -a -t f "KeyboardUtils.*" app/src/main/java/com/itsaky/androidide 2>/dev/null || true
fd -a -t f "KeyboardUtils.*" app/src/main/java 2>/dev/null || true
# 3) If we found the file, print it around isSoftInputVisible
# Use rg to get file path, then print a window around the definition line.
DEF_FILE=$(rg -n --type=kotlin "fun\s+isSoftInputVisible" app/src/main/java/com/itsaky/androidide -S | head -n 1 | cut -d: -f1 || true)
echo "DEF_FILE=$DEF_FILE"
if [ -n "$DEF_FILE" ]; then
rg -n --type=kotlin "fun\s+isSoftInputVisible" "$DEF_FILE"
sed -n '1,200p' "$DEF_FILE" | head -n 200
fiRepository: appdevforall/CodeOnTheGo
Length of output: 690
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate any definition/implementation of isSoftInputVisible and KeyboardUtils
rg -n --hidden --no-ignore --smart-case "isSoftInputVisible" . | head -n 50
echo "----"
rg -n --hidden --no-ignore --smart-case "object\s+KeyboardUtils|class\s+KeyboardUtils|KeyboardUtils" app/src/main/java | head -n 80Repository: appdevforall/CodeOnTheGo
Length of output: 1787
🌐 Web query:
com.blankj.utilcode.util.KeyboardUtils.isSoftInputVisible Activity signature ContextThemeWrapper ClassCastException
💡 Result:
There is no evidence (in the sources I found) that Blankj utilcode’s KeyboardUtils.isSoftInputVisible(Activity) has an “Activity signature ContextThemeWrapper ClassCastException”. Instead, the isSoftInputVisible implementation is type-safe in that it only accepts an Activity parameter and uses activity.getWindow/getDecorView—it does not cast a Context to Activity inside the method. 1) What Blankj’s code actually does - KeyboardUtils.isSoftInputVisible(@NonNull Activity activity) returns getDecorViewInvisibleHeight(activity.getWindow) > 0. [1] - getDecorViewInvisibleHeight(Window window) uses window.getDecorView, then decorView.getWindowVisibleDisplayFrame(outRect) and computes a delta from the decor view vs the visible frame. [1] So, within this implementation, there is no cast from ContextThemeWrapper (or any Context wrapper) to Activity. [1] 2) Why you might see ClassCastException involving ContextThemeWrapper + keyboard code - A ClassCastException like “android.view.ContextThemeWrapper cannot be cast to android.app.Activity” is a known pattern when code mistakenly does (Activity) getContext, but getContext is actually a ContextThemeWrapper rather than an Activity. - In React Native, keyboard visibility detection code in ReactRootView previously cast getContext directly to Activity, and the fix unwrapped the context using ContextWrapper.getBaseContext before casting. [2][3] This shows the general cause of the “ContextThemeWrapper -> Activity cast” failure is incorrect casting of an arbitrary Context; it is not an intrinsic issue with Blankj’s isSoftInputVisible(Activity) implementation. [2][3] 3) Android-soft-keyboard visibility detection guidance - Android’s official docs for keyboard/input-method visibility note that keyboard visibility behavior depends on window/view focus and windowSoftInputMode / flags, and recommends using InputMethodManager when you need to show it reliably. [4] This is consistent with the fact that any keyboard-visibility helper may produce incorrect results if it’s invoked with the wrong window/view state. [4] What to do if you are crashing - If you call KeyboardUtils.isSoftInputVisible(...) with something that is not actually an Activity (for example, passing view.getContext instead of the Activity), you can get crashes elsewhere in your stack. Ensure you pass a real Activity instance. - If you are using a framework view (e.g., React Native) that contains its own keyboard detection, check for code that casts getContext to Activity; apply the same pattern used in React Native’s fix: unwrap via ContextWrapper.getBaseContext (or use a safer way to obtain the owning Activity) before casting. [2][3] Top relevant sources: [1] https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/src/main/java/com/blankj/utilcode/util/KeyboardUtils.java [2] facebook/react-native@f7e35d4 [3] facebook/react-native#36121 [4] https://developer.android.com/develop/ui/views/touch-and-input/keyboard-input/visibility
Citations:
- 1: https://github.com/Blankj/AndroidUtilCode/blob/master/lib/utilcode/src/main/java/com/blankj/utilcode/util/KeyboardUtils.java
- 2: facebook/react-native@f7e35d4
- 3: Fix invalid context cast in ReactRootView facebook/react-native#36121
- 4: https://developer.android.com/develop/ui/views/touch-and-input/keyboard-input/visibility
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n --type=kotlin "class\s+EdgeToEdgeIDEActivity" app/src/main/java | head -n 20Repository: appdevforall/CodeOnTheGo
Length of output: 195
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n --type=kotlin "open\s+class\s+IDEActivity|abstract\s+class\s+IDEActivity|class\s+IDEActivity" app/src/main/java/com/itsaky/androidide/app app/src/main/java/com/itsaky/androidide | head -n 20Repository: appdevforall/CodeOnTheGo
Length of output: 290
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '1,120p' app/src/main/java/com/itsaky/androidide/app/IDEActivity.kt
echo "----"
rg -n --type=kotlin "open\s+class\s+BaseIDEActivity|abstract\s+class\s+BaseIDEActivity|class\s+BaseIDEActivity" app/src/main/java/com/itsaky/androidide/app app/src/main/java/com/itsaky/androidide | head -n 20
# Print the BaseIDEActivity file once found
BASE_FILE=$(rg -n --type=kotlin "class\s+BaseIDEActivity" app/src/main/java/com/itsaky/androidide/app app/src/main/java/com/itsaky/androidide | head -n 1 | cut -d: -f1 || true)
echo "BASE_FILE=$BASE_FILE"
if [ -n "$BASE_FILE" ]; then
sed -n '1,140p' "$BASE_FILE"
fiRepository: appdevforall/CodeOnTheGo
Length of output: 928
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Find BaseIDEActivity file
rg -n --hidden --no-ignore --smart-case "class\s+BaseIDEActivity" app/src/main/java | head -n 20
BASE_FILE=$(rg -n --hidden --no-ignore --smart-case "class\s+BaseIDEActivity" app/src/main/java | head -n 1 | cut -d: -f1 || true)
echo "BASE_FILE=$BASE_FILE"
if [ -n "$BASE_FILE" ]; then
sed -n '1,160p' "$BASE_FILE"
fi
# Also search for layoutInflater usage in BaseIDEActivity
rg -n --type=kotlin "layoutInflater" "$BASE_FILE" || trueRepository: appdevforall/CodeOnTheGo
Length of output: 50
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "---- rg BaseIDEActivity"
rg -n --hidden --no-ignore --smart-case "BaseIDEActivity" app/src/main/java | head -n 50 || true
echo "---- fd BaseIDEActivity"
fd -a -t f "BaseIDEActivity*" app/src/main/java 2>/dev/null || true
echo "---- fd *IDEActivity*"
fd -a -t f "*IDEActivity*" app/src/main/java/com/itsaky/androidide/app 2>/dev/null || trueRepository: appdevforall/CodeOnTheGo
Length of output: 249
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n --hidden --no-ignore --smart-case "BaseIDEActivity" . | head -n 50 || true
echo "----"
fd -a -t f "*BaseIDE*Activity*" . 2>/dev/null | head -n 50 || trueRepository: appdevforall/CodeOnTheGo
Length of output: 1920
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '1,140p' common/src/main/java/com/itsaky/androidide/app/BaseIDEActivity.kt
echo "----"
sed -n '140,260p' common/src/main/java/com/itsaky/androidide/app/BaseIDEActivity.ktRepository: appdevforall/CodeOnTheGo
Length of output: 3134
Avoid the unsafe contentBinding.root.context as Activity cast in FullscreenManager.applyFullscreen.
FullscreenManager.applyFullscreen casts the view context (contentBinding.root.context) to Activity to call KeyboardUtils.isSoftInputVisible(...). Since the view is inflated via BaseIDEActivity (an AppCompatActivity) and ActivityEditorBinding.inflate(layoutInflater), root.context can be a ContextThemeWrapper, making this cast a potential ClassCastException. Unwrap the context chain (or pass the owning activity) before calling KeyboardUtils.
🛡️ Proposed fix to safely resolve the Activity
- val isKeyboardOpen = KeyboardUtils.isSoftInputVisible(contentBinding.root.context as Activity)
- val targetState = if (isKeyboardOpen) BottomSheetBehavior.STATE_COLLAPSED else BottomSheetBehavior.STATE_HIDDEN
+ val activity = contentBinding.root.context.let { ctx ->
+ generateSequence(ctx) { (it as? ContextWrapper)?.baseContext }
+ .filterIsInstance<Activity>()
+ .firstOrNull()
+ }
+ val isKeyboardOpen = activity?.let { KeyboardUtils.isSoftInputVisible(it) } ?: false
+ val targetState = if (isKeyboardOpen) BottomSheetBehavior.STATE_COLLAPSED else BottomSheetBehavior.STATE_HIDDENAdd import android.content.ContextWrapper if you adopt this.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| val isKeyboardOpen = KeyboardUtils.isSoftInputVisible(contentBinding.root.context as Activity) | |
| val targetState = if (isKeyboardOpen) BottomSheetBehavior.STATE_COLLAPSED else BottomSheetBehavior.STATE_HIDDEN | |
| val activity = contentBinding.root.context.let { ctx -> | |
| generateSequence(ctx) { (it as? ContextWrapper)?.baseContext } | |
| .filterIsInstance<Activity>() | |
| .firstOrNull() | |
| } | |
| val isKeyboardOpen = activity?.let { KeyboardUtils.isSoftInputVisible(it) } ?: false | |
| val targetState = if (isKeyboardOpen) BottomSheetBehavior.STATE_COLLAPSED else BottomSheetBehavior.STATE_HIDDEN |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@app/src/main/java/com/itsaky/androidide/activities/editor/FullscreenManager.kt`
around lines 231 - 232, FullscreenManager.applyFullscreen currently unsafely
casts contentBinding.root.context to Activity for
KeyboardUtils.isSoftInputVisible; instead unwrap the view context by walking
ContextWrapper (while ctx is ContextWrapper set ctx = ctx.baseContext) until you
find an Activity, or accept/pass the owning Activity into FullscreenManager and
use that; then call KeyboardUtils.isSoftInputVisible(activity). Reference:
FullscreenManager.applyFullscreen, contentBinding.root.context, and
KeyboardUtils.isSoftInputVisible; add android.content.ContextWrapper import if
unwrapping.
|
|
||
| private fun applyPeekHeight() { | ||
| behavior.peekHeight = if (isImeVisible || isSearchModeActive) 0 else collapsedHeight.toInt() | ||
| behavior.peekHeight = if (isSearchModeActive) 0 else collapsedHeight.toInt() |
There was a problem hiding this comment.
Use roundToInt() for consistent and accurate float-to-int conversion.
The code uses toInt() here, which truncates the decimal part, while other locations in this file (lines 367, 375, 386, 392, 409) use roundToInt() for the same collapsedHeight property. Truncation can introduce off-by-one pixel errors in peek height calculations.
🔧 Proposed fix
- behavior.peekHeight = if (isSearchModeActive) 0 else collapsedHeight.toInt()
+ behavior.peekHeight = if (isSearchModeActive) 0 else collapsedHeight.roundToInt()📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| behavior.peekHeight = if (isSearchModeActive) 0 else collapsedHeight.toInt() | |
| behavior.peekHeight = if (isSearchModeActive) 0 else collapsedHeight.roundToInt() |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/src/main/java/com/itsaky/androidide/ui/EditorBottomSheet.kt` at line 357,
Replace the float-to-int conversion for the bottom sheet peek height to use
rounding instead of truncation: locate the assignment to behavior.peekHeight in
EditorBottomSheet (the line using isSearchModeActive and collapsedHeight) and
change the conversion of collapsedHeight to use roundToInt() so it matches other
uses in this file and avoids off-by-one pixel errors.
DrawerLayoutbackground showing above the keyboard