Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import android.graphics.Rect
import android.os.Build
import android.view.View
import android.view.Window
import android.view.WindowManager
import kotlin.math.roundToInt

object ViewUtils {
Expand All @@ -19,19 +20,32 @@ object ViewUtils {
// Due to differences in accounting for keyboard, navigation bar, and status bar between
// Android versions have different implementation here
fun getWindowHeight(activity: Activity): Int {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
getWindowHeightAPI30Plus(activity)
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
getWindowHeightAPI23Plus(activity)
} else {
getWindowHeightLollipop(activity)
}
}

@Suppress("DEPRECATION")
private fun getDisplaySizeY(activity: Activity): Int {
val point = Point()
activity.windowManager.defaultDisplay.getSize(point)
return point.y
}

@TargetApi(Build.VERSION_CODES.R)
private fun getWindowHeightAPI30Plus(activity: Activity): Int {
val windowMetrics = activity.windowManager.currentWindowMetrics
val insets =
windowMetrics.windowInsets.getInsetsIgnoringVisibility(
android.view.WindowInsets.Type.systemBars(),
)
return windowMetrics.bounds.height() - insets.top - insets.bottom
}

// Requirement: Ensure DecorView is ready by using OSViewUtils.decorViewReady
@TargetApi(Build.VERSION_CODES.M)
private fun getWindowHeightAPI23Plus(activity: Activity): Int {
Expand Down Expand Up @@ -87,7 +101,10 @@ object ViewUtils {
}

fun getFullbleedWindowWidth(activity: Activity): Int {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val windowMetrics = activity.windowManager.currentWindowMetrics
windowMetrics.bounds.width()
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val decorView = activity.window.decorView
decorView.width
} else {
Expand All @@ -96,6 +113,20 @@ object ViewUtils {
}

fun getWindowWidth(activity: Activity): Int {
return getWindowVisibleDisplayFrame(activity).width()
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
getWindowWidthAPI30Plus(activity)
} else {
getWindowVisibleDisplayFrame(activity).width()
}
}

@TargetApi(Build.VERSION_CODES.R)
private fun getWindowWidthAPI30Plus(activity: Activity): Int {
val windowMetrics = activity.windowManager.currentWindowMetrics
val insets =
windowMetrics.windowInsets.getInsetsIgnoringVisibility(
android.view.WindowInsets.Type.systemBars(),
)
return windowMetrics.bounds.width() - insets.left - insets.right
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ class ApplicationService() : IApplicationService, ActivityLifecycleCallbacks, On

val configuration =
object : ComponentCallbacks {
private var lastScreenWidthDp: Int = 0
private var lastScreenHeightDp: Int = 0

override fun onConfigurationChanged(newConfig: Configuration) {
// If Activity contains the configChanges orientation flag, re-create the view this way
if (current != null &&
Expand All @@ -93,6 +96,27 @@ class ApplicationService() : IApplicationService, ActivityLifecycleCallbacks, On
) {
onOrientationChanged(newConfig.orientation, current!!)
}

// Handle foldable device screen size changes (fold/unfold events)
// Foldable devices trigger CONFIG_SCREEN_SIZE without orientation change
if (current != null && hasScreenSizeChanged(newConfig)) {
Logging.debug(
"ApplicationService.onConfigurationChanged: Screen size changed " +
"(foldable device fold/unfold detected) - " +
"width: ${newConfig.screenWidthDp}dp, height: ${newConfig.screenHeightDp}dp",
)
onScreenSizeChanged(current!!)
}
lastScreenWidthDp = newConfig.screenWidthDp
lastScreenHeightDp = newConfig.screenHeightDp
}

private fun hasScreenSizeChanged(newConfig: Configuration): Boolean {
if (lastScreenWidthDp == 0 && lastScreenHeightDp == 0) {
return false
}
return newConfig.screenWidthDp != lastScreenWidthDp ||
newConfig.screenHeightDp != lastScreenHeightDp
}

override fun onLowMemory() {}
Expand Down Expand Up @@ -368,6 +392,23 @@ class ApplicationService() : IApplicationService, ActivityLifecycleCallbacks, On
handleFocus()
}

/**
* Handles screen size changes that occur on foldable devices when folding/unfolding.
* Unlike orientation changes, foldable devices can change screen dimensions significantly
* without changing orientation (e.g., Samsung Galaxy Fold going from cover screen to main screen).
* This triggers the same view recreation flow as orientation changes to ensure IAMs are
* properly resized and repositioned.
*/
private fun onScreenSizeChanged(activity: Activity) {
// Remove view
activityLifecycleNotifier.fire { it.onActivityStopped(activity) }

// Show view with new dimensions
activityLifecycleNotifier.fire { it.onActivityAvailable(activity) }

activity.window.decorView.viewTreeObserver.addOnGlobalLayoutListener(this)
}

private fun handleLostFocus() {
if (isInForeground) {
Logging.debug("ApplicationService.handleLostFocus: application is now out of focus")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ internal class WebViewManager(
showMessageView(lastPageHeight)
}
} else {
// Activity rotated
// Activity rotated or screen size changed (e.g., foldable device fold/unfold)
calculateHeightAndShowWebViewAfterNewActivity()
}
}
Expand Down
Loading