ViewCompat.getWindowInsetsController is deprecated - which alternative to use?
Asked Answered
R

1

22

After updating to Android Gradle plugin version 7.2.2 a warning is being given on the default Theme.kt file for Jetpack Compose projects:

ViewCompat.getWindowInsetsController is deprecated

This warning comes from a default implementation provided during Project Scaffolding:

/* snip */
val view = LocalView.current
    if (!view.isInEditMode) {
        SideEffect {
            (view.context as Activity).window.statusBarColor = colorScheme.primary.toArgb()
            ViewCompat.getWindowInsetsController(view)?.isAppearanceLightStatusBars = darkTheme // <--- This triggers a deprecation warning
        }
    }

Documentation recommends one to use the WindowCompat.getInsetsController instead - but that function needs access to both a view and a window.

Is there an easy path forward to resolve this Warning without ignoring it?

Roxie answered 7/8, 2022 at 21:52 Comment(0)
R
30

Complete changes that must be done available here

That if snippet exists just because of the Component Preview within Android Studio - where there's never an available Activity to attach to! (When you're actually running an Application your view won't be in edit mode - thus actually running the inner statement only in real scenarios).

Since it's logically only executed within real application we can do some casts to retrieve the current window by assuming that the view.context is an Activity. If that's an Activity you can access the currentWindow property and use that as the window parameter for the recommended approach.

So we end up with the following code - with some extra refactoring to reduce code duplication - that casts the current view's context to an Activity and does the appropriate settings:

@Composable
fun YourAppTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    // Dynamic color is available on Android 12+
    dynamicColor: Boolean = true,
    content: @Composable () -> Unit
) {
    val colorScheme = pickColorScheme(dynamicColor, darkTheme)
    val view = LocalView.current

    if (!view.isInEditMode) {
        /* getting the current window by tapping into the Activity */
        val currentWindow = (view.context as? Activity)?.window
            ?: throw Exception("Not in an activity - unable to get Window reference")

        SideEffect {
            /* the default code did the same cast here - might as well use our new variable! */
            currentWindow.statusBarColor = colorScheme.primary.toArgb()
            /* accessing the insets controller to change appearance of the status bar, with 100% less deprecation warnings */
            WindowCompat.getInsetsController(currentWindow, view).isAppearanceLightStatusBars =
                darkTheme
        }
    }

    MaterialTheme(
        colorScheme = colorScheme,
        typography = Typography,
        content = content
    )
}
Roxie answered 7/8, 2022 at 21:52 Comment(2)
Why would you throw an Exception?Arvo
In all expected 'normal' contexts an Activity, and thus its attributes, will be available for this routine to access thus why I went for an Exception. If somehow we aren't in edit mode and there's no available Activity for the application whatsoever something is wrong and we cannot guarantee anything will behave as expected within the Theme.Roxie

© 2022 - 2024 — McMap. All rights reserved.