1 /*
2  * Copyright 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.compose.foundation.layout
18 
19 import androidx.compose.runtime.Composable
20 import androidx.compose.runtime.Immutable
21 import androidx.compose.runtime.ReadOnlyComposable
22 import androidx.compose.runtime.Stable
23 import androidx.compose.runtime.getValue
24 import androidx.compose.runtime.mutableStateOf
25 import androidx.compose.runtime.setValue
26 import androidx.compose.ui.Modifier
27 import androidx.compose.ui.platform.LocalDensity
28 import androidx.compose.ui.unit.Density
29 import androidx.compose.ui.unit.Dp
30 import androidx.compose.ui.unit.LayoutDirection
31 import androidx.compose.ui.unit.dp
32 
33 /**
34  * A representation of window insets that tracks access to enable recomposition, relayout, and
35  * redrawing when values change. These values should not be read during composition to avoid doing
36  * composition for every frame of an animation. Use methods like [Modifier.windowInsetsPadding],
37  * [Modifier.systemBarsPadding], and [Modifier.windowInsetsTopHeight] for Modifiers that will not
38  * cause recomposition when values change.
39  *
40  * Use the [WindowInsets.Companion] extensions to retrieve [WindowInsets] for the current window.
41  */
42 @Stable
43 interface WindowInsets {
44     /** The space, in pixels, at the left of the window that the inset represents. */
getLeftnull45     fun getLeft(density: Density, layoutDirection: LayoutDirection): Int
46 
47     /** The space, in pixels, at the top of the window that the inset represents. */
48     fun getTop(density: Density): Int
49 
50     /** The space, in pixels, at the right of the window that the inset represents. */
51     fun getRight(density: Density, layoutDirection: LayoutDirection): Int
52 
53     /** The space, in pixels, at the bottom of the window that the inset represents. */
54     fun getBottom(density: Density): Int
55 
56     companion object
57 }
58 
59 /**
60  * A [WindowInsets] whose values can change without changing the instance. This is useful to avoid
61  * recomposition when [WindowInsets] can change.
62  *
63  * @sample androidx.compose.foundation.layout.samples.withConsumedInsetsSample
64  *
65  * Note: This API as experimental since it doesn't enforce the right consumption patterns.
66  */
67 @ExperimentalLayoutApi
68 class MutableWindowInsets(initialInsets: WindowInsets = WindowInsets(0, 0, 0, 0)) : WindowInsets {
69     /**
70      * The [WindowInsets] that are used for [left][getLeft], [top][getTop], [right][getRight], and
71      * [bottom][getBottom] values.
72      */
73     var insets by mutableStateOf(initialInsets)
74 
75     override fun getLeft(density: Density, layoutDirection: LayoutDirection): Int =
76         insets.getLeft(density, layoutDirection)
77 
78     override fun getTop(density: Density): Int = insets.getTop(density)
79 
80     override fun getRight(density: Density, layoutDirection: LayoutDirection): Int =
81         insets.getRight(density, layoutDirection)
82 
83     override fun getBottom(density: Density): Int = insets.getBottom(density)
84 }
85 
86 /**
87  * [WindowInsetsSides] is used in [WindowInsets.only] to define which sides of the [WindowInsets]
88  * should apply.
89  */
90 @kotlin.jvm.JvmInline
91 value class WindowInsetsSides private constructor(private val value: Int) {
92     /** Returns a [WindowInsetsSides] containing sides defied in [sides] and the sides in `this`. */
plusnull93     operator fun plus(sides: WindowInsetsSides): WindowInsetsSides =
94         WindowInsetsSides(value or sides.value)
95 
96     internal fun hasAny(sides: WindowInsetsSides): Boolean = (value and sides.value) != 0
97 
98     override fun toString(): String = "WindowInsetsSides(${valueToString()})"
99 
100     private fun valueToString(): String = buildString {
101         fun appendPlus(text: String) {
102             if (isNotEmpty()) append('+')
103             append(text)
104         }
105 
106         if (value and Start.value == Start.value) appendPlus("Start")
107         if (value and Left.value == Left.value) appendPlus("Left")
108         if (value and Top.value == Top.value) appendPlus("Top")
109         if (value and End.value == End.value) appendPlus("End")
110         if (value and Right.value == Right.value) appendPlus("Right")
111         if (value and Bottom.value == Bottom.value) appendPlus("Bottom")
112     }
113 
114     companion object {
115         //     _---- allowLeft  in ltr
116         //    /
117         //    | _--- allowRight in ltr
118         //    |/
119         //    || _-- allowLeft  in rtl
120         //    ||/
121         //    ||| _- allowRight in rtl
122         //    |||/
123         //    VVVV
124         //    Mask   = ----
125         //
126         //    Left   = 1010
127         //    Right  = 0101
128         //    Start  = 1001
129         //    End    = 0110
130 
131         internal val AllowLeftInLtr = WindowInsetsSides(1 shl 3)
132         internal val AllowRightInLtr = WindowInsetsSides(1 shl 2)
133         internal val AllowLeftInRtl = WindowInsetsSides(1 shl 1)
134         internal val AllowRightInRtl = WindowInsetsSides(1 shl 0)
135 
136         /**
137          * Indicates a [WindowInsets] start side, which is left or right depending on
138          * [LayoutDirection]. If [LayoutDirection.Ltr], [Start] is the left side. If
139          * [LayoutDirection.Rtl], [Start] is the right side.
140          *
141          * Use [Left] or [Right] if the physical direction is required.
142          */
143         val Start = AllowLeftInLtr + AllowRightInRtl
144 
145         /**
146          * Indicates a [WindowInsets] end side, which is left or right depending on
147          * [LayoutDirection]. If [LayoutDirection.Ltr], [End] is the right side. If
148          * [LayoutDirection.Rtl], [End] is the left side.
149          *
150          * Use [Left] or [Right] if the physical direction is required.
151          */
152         val End = AllowRightInLtr + AllowLeftInRtl
153 
154         /** Indicates a [WindowInsets] top side. */
155         val Top = WindowInsetsSides(1 shl 4)
156 
157         /** Indicates a [WindowInsets] bottom side. */
158         val Bottom = WindowInsetsSides(1 shl 5)
159 
160         /**
161          * Indicates a [WindowInsets] left side. Most layouts will prefer using [Start] or [End] to
162          * account for [LayoutDirection].
163          */
164         val Left = AllowLeftInLtr + AllowLeftInRtl
165 
166         /**
167          * Indicates a [WindowInsets] right side. Most layouts will prefer using [Start] or [End] to
168          * account for [LayoutDirection].
169          */
170         val Right = AllowRightInLtr + AllowRightInRtl
171 
172         /**
173          * Indicates a [WindowInsets] horizontal sides. This is a combination of [Left] and [Right]
174          * sides, or [Start] and [End] sides.
175          */
176         val Horizontal = Left + Right
177 
178         /** Indicates a [WindowInsets] [Top] and [Bottom] sides. */
179         val Vertical = Top + Bottom
180     }
181 }
182 
183 /** Returns a [WindowInsets] that has the maximum values of this [WindowInsets] and [insets]. */
WindowInsetsnull184 fun WindowInsets.union(insets: WindowInsets): WindowInsets = UnionInsets(this, insets)
185 
186 /**
187  * Returns the values in this [WindowInsets] that are not also in [insets]. For example, if this
188  * [WindowInsets] has a [WindowInsets.getTop] value of `10` and [insets] has a [WindowInsets.getTop]
189  * value of `8`, the returned [WindowInsets] will have a [WindowInsets.getTop] value of `2`.
190  *
191  * Negative values are never returned. For example if [insets] has a [WindowInsets.getTop] of `10`
192  * and this has a [WindowInsets.getTop] of `0`, the returned [WindowInsets] will have a
193  * [WindowInsets.getTop] value of `0`.
194  */
195 fun WindowInsets.exclude(insets: WindowInsets): WindowInsets = ExcludeInsets(this, insets)
196 
197 /**
198  * Returns a [WindowInsets] that has values of this, added to the values of [insets]. For example,
199  * if this has a top of 10 and insets has a top of 5, the returned [WindowInsets] will have a top
200  * of 15.
201  */
202 fun WindowInsets.add(insets: WindowInsets): WindowInsets = AddedInsets(this, insets)
203 
204 /**
205  * Returns a [WindowInsets] that eliminates all dimensions except the ones that are enabled. For
206  * example, to have a [WindowInsets] at the bottom of the screen, pass [WindowInsetsSides.Bottom].
207  */
208 fun WindowInsets.only(sides: WindowInsetsSides): WindowInsets = LimitInsets(this, sides)
209 
210 /**
211  * Convert a [WindowInsets] to a [PaddingValues] and uses [LocalDensity] for DP to pixel conversion.
212  * [PaddingValues] can be passed to some containers to pad internal content so that it doesn't
213  * overlap the insets when fully scrolled. Ensure that the insets are
214  * [consumed][consumeWindowInsets] after the padding is applied if insets are to be used further
215  * down the hierarchy.
216  *
217  * @sample androidx.compose.foundation.layout.samples.paddingValuesSample
218  */
219 @ReadOnlyComposable
220 @Composable
221 fun WindowInsets.asPaddingValues(): PaddingValues = InsetsPaddingValues(this, LocalDensity.current)
222 
223 /**
224  * Convert a [WindowInsets] to a [PaddingValues] and uses [density] for DP to pixel conversion.
225  * [PaddingValues] can be passed to some containers to pad internal content so that it doesn't
226  * overlap the insets when fully scrolled. Ensure that the insets are
227  * [consumed][consumeWindowInsets] after the padding is applied if insets are to be used further
228  * down the hierarchy.
229  *
230  * @sample androidx.compose.foundation.layout.samples.paddingValuesSample
231  */
232 fun WindowInsets.asPaddingValues(density: Density): PaddingValues =
233     InsetsPaddingValues(this, density)
234 
235 /** Convert a [PaddingValues] to a [WindowInsets]. */
236 internal fun PaddingValues.asInsets(): WindowInsets = PaddingValuesInsets(this)
237 
238 /** Create a [WindowInsets] with fixed dimensions of 0 on all sides. */
239 fun WindowInsets(): WindowInsets = EmptyWindowInsets
240 
241 /**
242  * Create a [WindowInsets] with fixed dimensions.
243  *
244  * @sample androidx.compose.foundation.layout.samples.insetsInt
245  */
246 fun WindowInsets(left: Int = 0, top: Int = 0, right: Int = 0, bottom: Int = 0): WindowInsets =
247     FixedIntInsets(left, top, right, bottom)
248 
249 /**
250  * Create a [WindowInsets] with fixed dimensions, using [Dp] values.
251  *
252  * @sample androidx.compose.foundation.layout.samples.insetsDp
253  */
254 fun WindowInsets(
255     left: Dp = 0.dp,
256     top: Dp = 0.dp,
257     right: Dp = 0.dp,
258     bottom: Dp = 0.dp
259 ): WindowInsets = FixedDpInsets(left, top, right, bottom)
260 
261 @Immutable
262 private class FixedIntInsets(
263     private val leftVal: Int,
264     private val topVal: Int,
265     private val rightVal: Int,
266     private val bottomVal: Int
267 ) : WindowInsets {
268     override fun getLeft(density: Density, layoutDirection: LayoutDirection): Int = leftVal
269 
270     override fun getTop(density: Density): Int = topVal
271 
272     override fun getRight(density: Density, layoutDirection: LayoutDirection): Int = rightVal
273 
274     override fun getBottom(density: Density): Int = bottomVal
275 
276     override fun toString(): String {
277         return "Insets(left=$leftVal, top=$topVal, right=$rightVal, bottom=$bottomVal)"
278     }
279 
280     override fun equals(other: Any?): Boolean {
281         if (this === other) {
282             return true
283         }
284         if (other !is FixedIntInsets) {
285             return false
286         }
287 
288         return leftVal == other.leftVal &&
289             topVal == other.topVal &&
290             rightVal == other.rightVal &&
291             bottomVal == other.bottomVal
292     }
293 
294     override fun hashCode(): Int {
295         var result = leftVal
296         result = 31 * result + topVal
297         result = 31 * result + rightVal
298         result = 31 * result + bottomVal
299         return result
300     }
301 }
302 
303 @Immutable
304 private class FixedDpInsets(
305     private val leftDp: Dp,
306     private val topDp: Dp,
307     private val rightDp: Dp,
308     private val bottomDp: Dp
309 ) : WindowInsets {
getLeftnull310     override fun getLeft(density: Density, layoutDirection: LayoutDirection) =
311         with(density) { leftDp.roundToPx() }
312 
<lambda>null313     override fun getTop(density: Density) = with(density) { topDp.roundToPx() }
314 
getRightnull315     override fun getRight(density: Density, layoutDirection: LayoutDirection) =
316         with(density) { rightDp.roundToPx() }
317 
<lambda>null318     override fun getBottom(density: Density) = with(density) { bottomDp.roundToPx() }
319 
toStringnull320     override fun toString(): String {
321         return "Insets(left=$leftDp, top=$topDp, right=$rightDp, bottom=$bottomDp)"
322     }
323 
equalsnull324     override fun equals(other: Any?): Boolean {
325         if (this === other) {
326             return true
327         }
328         if (other !is FixedDpInsets) {
329             return false
330         }
331 
332         return leftDp == other.leftDp &&
333             topDp == other.topDp &&
334             rightDp == other.rightDp &&
335             bottomDp == other.bottomDp
336     }
337 
hashCodenull338     override fun hashCode(): Int {
339         var result = leftDp.hashCode()
340         result = 31 * result + topDp.hashCode()
341         result = 31 * result + rightDp.hashCode()
342         result = 31 * result + bottomDp.hashCode()
343         return result
344     }
345 }
346 
347 private val EmptyWindowInsets = FixedIntInsets(0, 0, 0, 0)
348 
349 /**
350  * An [WindowInsets] that comes straight from [androidx.core.graphics.Insets], whose value can be
351  * updated.
352  */
353 @Stable
354 internal class ValueInsets(insets: InsetsValues, val name: String) : WindowInsets {
355     internal var value by mutableStateOf(insets)
356 
getLeftnull357     override fun getLeft(density: Density, layoutDirection: LayoutDirection): Int = value.left
358 
359     override fun getTop(density: Density) = value.top
360 
361     override fun getRight(density: Density, layoutDirection: LayoutDirection) = value.right
362 
363     override fun getBottom(density: Density) = value.bottom
364 
365     override fun equals(other: Any?): Boolean {
366         if (other === this) {
367             return true
368         }
369         if (other !is ValueInsets) {
370             return false
371         }
372         return value == other.value
373     }
374 
hashCodenull375     override fun hashCode(): Int {
376         return name.hashCode()
377     }
378 
toStringnull379     override fun toString(): String {
380         return "$name(left=${value.left}, top=${value.top}, " +
381             "right=${value.right}, bottom=${value.bottom})"
382     }
383 }
384 
385 @Immutable
386 internal class InsetsValues(val left: Int, val top: Int, val right: Int, val bottom: Int) {
equalsnull387     override fun equals(other: Any?): Boolean {
388         if (this === other) {
389             return true
390         }
391         if (other !is InsetsValues) {
392             return false
393         }
394 
395         return left == other.left &&
396             top == other.top &&
397             right == other.right &&
398             bottom == other.bottom
399     }
400 
hashCodenull401     override fun hashCode(): Int {
402         var result = left
403         result = 31 * result + top
404         result = 31 * result + right
405         result = 31 * result + bottom
406         return result
407     }
408 
toStringnull409     override fun toString(): String =
410         "InsetsValues(left=$left, top=$top, right=$right, bottom=$bottom)"
411 }
412 
413 /**
414  * An [WindowInsets] that includes the maximum value of [first] and [second] as returned from
415  * [WindowInsets.union].
416  */
417 @Stable
418 private class UnionInsets(private val first: WindowInsets, private val second: WindowInsets) :
419     WindowInsets {
420     override fun getLeft(density: Density, layoutDirection: LayoutDirection) =
421         maxOf(first.getLeft(density, layoutDirection), second.getLeft(density, layoutDirection))
422 
423     override fun getTop(density: Density) = maxOf(first.getTop(density), second.getTop(density))
424 
425     override fun getRight(density: Density, layoutDirection: LayoutDirection) =
426         maxOf(first.getRight(density, layoutDirection), second.getRight(density, layoutDirection))
427 
428     override fun getBottom(density: Density) =
429         maxOf(first.getBottom(density), second.getBottom(density))
430 
431     override fun hashCode(): Int = first.hashCode() + second.hashCode() * 31
432 
433     override fun equals(other: Any?): Boolean {
434         if (this === other) {
435             return true
436         }
437         if (other !is UnionInsets) {
438             return false
439         }
440         return other.first == first && other.second == second
441     }
442 
443     override fun toString(): String = "($first ∪ $second)"
444 }
445 
446 /** An [WindowInsets] that includes the added value of [first] to [second]. */
447 @Stable
448 private class AddedInsets(private val first: WindowInsets, private val second: WindowInsets) :
449     WindowInsets {
getLeftnull450     override fun getLeft(density: Density, layoutDirection: LayoutDirection) =
451         first.getLeft(density, layoutDirection) + second.getLeft(density, layoutDirection)
452 
453     override fun getTop(density: Density) = first.getTop(density) + second.getTop(density)
454 
455     override fun getRight(density: Density, layoutDirection: LayoutDirection) =
456         first.getRight(density, layoutDirection) + second.getRight(density, layoutDirection)
457 
458     override fun getBottom(density: Density) = first.getBottom(density) + second.getBottom(density)
459 
460     override fun hashCode(): Int = first.hashCode() + second.hashCode() * 31
461 
462     override fun equals(other: Any?): Boolean {
463         if (this === other) {
464             return true
465         }
466         if (other !is AddedInsets) {
467             return false
468         }
469         return other.first == first && other.second == second
470     }
471 
toStringnull472     override fun toString(): String = "($first + $second)"
473 }
474 
475 /**
476  * An [WindowInsets] that includes the value of [included] that is not included in [excluded] as
477  * returned from [WindowInsets.exclude].
478  */
479 @Stable
480 private class ExcludeInsets(
481     private val included: WindowInsets,
482     private val excluded: WindowInsets
483 ) : WindowInsets {
484     override fun getLeft(density: Density, layoutDirection: LayoutDirection) =
485         (included.getLeft(density, layoutDirection) - excluded.getLeft(density, layoutDirection))
486             .coerceAtLeast(0)
487 
488     override fun getTop(density: Density) =
489         (included.getTop(density) - excluded.getTop(density)).coerceAtLeast(0)
490 
491     override fun getRight(density: Density, layoutDirection: LayoutDirection) =
492         (included.getRight(density, layoutDirection) - excluded.getRight(density, layoutDirection))
493             .coerceAtLeast(0)
494 
495     override fun getBottom(density: Density) =
496         (included.getBottom(density) - excluded.getBottom(density)).coerceAtLeast(0)
497 
498     override fun toString(): String = "($included - $excluded)"
499 
500     override fun equals(other: Any?): Boolean {
501         if (this === other) {
502             return true
503         }
504         if (other !is ExcludeInsets) {
505             return false
506         }
507 
508         return (other.included == included && other.excluded == excluded)
509     }
510 
511     override fun hashCode(): Int = 31 * included.hashCode() + excluded.hashCode()
512 }
513 
514 /** An [WindowInsets] calculated from [paddingValues]. */
515 @Stable
516 private class PaddingValuesInsets(private val paddingValues: PaddingValues) : WindowInsets {
getLeftnull517     override fun getLeft(density: Density, layoutDirection: LayoutDirection) =
518         with(density) { paddingValues.calculateLeftPadding(layoutDirection).roundToPx() }
519 
getTopnull520     override fun getTop(density: Density) =
521         with(density) { paddingValues.calculateTopPadding().roundToPx() }
522 
getRightnull523     override fun getRight(density: Density, layoutDirection: LayoutDirection) =
524         with(density) { paddingValues.calculateRightPadding(layoutDirection).roundToPx() }
525 
getBottomnull526     override fun getBottom(density: Density) =
527         with(density) { paddingValues.calculateBottomPadding().roundToPx() }
528 
toStringnull529     override fun toString(): String {
530         val layoutDirection = LayoutDirection.Ltr
531         val start = paddingValues.calculateLeftPadding(layoutDirection)
532         val top = paddingValues.calculateTopPadding()
533         val end = paddingValues.calculateRightPadding(layoutDirection)
534         val bottom = paddingValues.calculateBottomPadding()
535         return "PaddingValues($start, $top, $end, $bottom)"
536     }
537 
equalsnull538     override fun equals(other: Any?): Boolean {
539         if (this === other) {
540             return true
541         }
542         if (other !is PaddingValuesInsets) {
543             return false
544         }
545 
546         return other.paddingValues == paddingValues
547     }
548 
hashCodenull549     override fun hashCode(): Int = paddingValues.hashCode()
550 }
551 
552 @Stable
553 private class LimitInsets(val insets: WindowInsets, val sides: WindowInsetsSides) : WindowInsets {
554     override fun getLeft(density: Density, layoutDirection: LayoutDirection): Int {
555         val layoutDirectionSide =
556             if (layoutDirection == LayoutDirection.Ltr) {
557                 WindowInsetsSides.AllowLeftInLtr
558             } else {
559                 WindowInsetsSides.AllowLeftInRtl
560             }
561         val allowLeft = sides.hasAny(layoutDirectionSide)
562         return if (allowLeft) {
563             insets.getLeft(density, layoutDirection)
564         } else {
565             0
566         }
567     }
568 
569     override fun getTop(density: Density): Int =
570         if (sides.hasAny(WindowInsetsSides.Top)) insets.getTop(density) else 0
571 
572     override fun getRight(density: Density, layoutDirection: LayoutDirection): Int {
573         val layoutDirectionSide =
574             if (layoutDirection == LayoutDirection.Ltr) {
575                 WindowInsetsSides.AllowRightInLtr
576             } else {
577                 WindowInsetsSides.AllowRightInRtl
578             }
579         val allowRight = sides.hasAny(layoutDirectionSide)
580         return if (allowRight) {
581             insets.getRight(density, layoutDirection)
582         } else {
583             0
584         }
585     }
586 
587     override fun getBottom(density: Density): Int =
588         if (sides.hasAny(WindowInsetsSides.Bottom)) insets.getBottom(density) else 0
589 
590     override fun equals(other: Any?): Boolean {
591         if (this === other) {
592             return true
593         }
594         if (other !is LimitInsets) {
595             return false
596         }
597         return insets == other.insets && sides == other.sides
598     }
599 
600     override fun hashCode(): Int {
601         var result = insets.hashCode()
602         result = 31 * result + sides.hashCode()
603         return result
604     }
605 
606     override fun toString(): String = "($insets only $sides)"
607 }
608 
609 @Stable
610 private class InsetsPaddingValues(val insets: WindowInsets, private val density: Density) :
611     PaddingValues {
calculateLeftPaddingnull612     override fun calculateLeftPadding(layoutDirection: LayoutDirection) =
613         with(density) { insets.getLeft(this, layoutDirection).toDp() }
614 
<lambda>null615     override fun calculateTopPadding() = with(density) { insets.getTop(this).toDp() }
616 
calculateRightPaddingnull617     override fun calculateRightPadding(layoutDirection: LayoutDirection) =
618         with(density) { insets.getRight(this, layoutDirection).toDp() }
619 
<lambda>null620     override fun calculateBottomPadding() = with(density) { insets.getBottom(this).toDp() }
621 
toStringnull622     override fun toString(): String {
623         return "InsetsPaddingValues(insets=$insets, density=$density)"
624     }
625 
equalsnull626     override fun equals(other: Any?): Boolean {
627         if (this === other) {
628             return true
629         }
630         if (other !is InsetsPaddingValues) {
631             return false
632         }
633         return insets == other.insets && density == other.density
634     }
635 
hashCodenull636     override fun hashCode(): Int {
637         var result = insets.hashCode()
638         result = 31 * result + density.hashCode()
639         return result
640     }
641 }
642 
643 /** An insets type representing the window of a caption bar. */
644 expect val WindowInsets.Companion.captionBar: WindowInsets
645     @Composable get
646 
647 /** This [WindowInsets] represents the area with the display cutout (e.g. for camera). */
648 expect val WindowInsets.Companion.displayCutout: WindowInsets
649     @Composable get
650 
651 /** An insets type representing the window of the software keyboard. */
652 expect val WindowInsets.Companion.ime: WindowInsets
653     @Composable get
654 
655 /**
656  * These insets represent the space where system gestures have priority over application gestures.
657  */
658 expect val WindowInsets.Companion.mandatorySystemGestures: WindowInsets
659     @Composable get
660 
661 /**
662  * These insets represent where system UI places navigation bars. Interactive UI should avoid the
663  * navigation bars area.
664  */
665 expect val WindowInsets.Companion.navigationBars: WindowInsets
666     @Composable get
667 
668 /** These insets represent status bar. */
669 expect val WindowInsets.Companion.statusBars: WindowInsets
670     @Composable get
671 
672 /**
673  * These insets represent all system bars. Includes [statusBars], [captionBar] as well as
674  * [navigationBars], but not [ime].
675  */
676 expect val WindowInsets.Companion.systemBars: WindowInsets
677     @Composable get
678 
679 /**
680  * The [systemGestures] insets represent the area of a window where system gestures have priority
681  * and may consume some or all touch input, e.g. due to the system bar occupying it, or it being
682  * reserved for touch-only gestures.
683  */
684 expect val WindowInsets.Companion.systemGestures: WindowInsets
685     @Composable get
686 
687 /** Returns the tappable element insets. */
688 expect val WindowInsets.Companion.tappableElement: WindowInsets
689     @Composable get
690 
691 /** The insets for the curved areas in a waterfall display. */
692 expect val WindowInsets.Companion.waterfall: WindowInsets
693     @Composable get
694 
695 /**
696  * The insets that include areas where content may be covered by other drawn content. This includes
697  * all [systemBars], [displayCutout], and [ime].
698  */
699 expect val WindowInsets.Companion.safeDrawing: WindowInsets
700     @Composable get
701 
702 /**
703  * The insets that include areas where gestures may be confused with other input, including
704  * [systemGestures], [mandatorySystemGestures], [waterfall], and [tappableElement].
705  */
706 expect val WindowInsets.Companion.safeGestures: WindowInsets
707     @Composable get
708 
709 /**
710  * The insets that include all areas that may be drawn over or have gesture confusion, including
711  * everything in [safeDrawing] and [safeGestures].
712  */
713 expect val WindowInsets.Companion.safeContent: WindowInsets
714     @Composable get
715