1 package com.android.permissioncontroller.safetycenter.ui
2 
3 import android.content.Context
4 import android.util.AttributeSet
5 import android.view.View.MeasureSpec.EXACTLY
6 import android.widget.LinearLayout
7 import android.widget.Space
8 import androidx.core.view.children
9 
10 /**
11  * A [LinearLayout] that requires all its children (except [Space]s) to be the same width. The
12  * layout is horizontal, unless the buttons don't fit in which case it moves to vertical.
13  *
14  * Assumes its children are all WRAP_CONTENT width and that it is some fixed width (either
15  * MATCH_PARENT or sized by constraint - not WRAP_CONTENT itself).
16  */
17 class EqualWidthContainer @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
18     LinearLayout(context, attrs) {
19 
onMeasurenull20     override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
21         // super.onMeasure will cause all children to be measured in the default way
22         super.onMeasure(widthMeasureSpec, heightMeasureSpec)
23 
24         // Separate children into spaces and non-spaces
25         val (spaces, nonSpaceItems) = children.partition { it is Space }
26         val neededWidthPerNonSpaceItem =
27             try {
28                 nonSpaceItems.maxOf { it.measuredWidth }
29             } catch (e: NoSuchElementException) {
30                 0
31             }
32         val neededWidth = neededWidthPerNonSpaceItem * nonSpaceItems.count()
33 
34         // Switch between horizontal or vertical layout as needed
35         val availableWidth =
36             MeasureSpec.getSize(widthMeasureSpec) - spaces.sumOf { it.measuredWidth }
37         orientation = if (neededWidth <= availableWidth) HORIZONTAL else VERTICAL
38 
39         // Measure again now orientation has changed
40         super.onMeasure(widthMeasureSpec, heightMeasureSpec)
41 
42         // Re-measure all the children with EXACT width (using previously calculated height)
43         nonSpaceItems.forEach {
44             it.measure(
45                 MeasureSpec.makeMeasureSpec(neededWidthPerNonSpaceItem, EXACTLY),
46                 MeasureSpec.makeMeasureSpec(it.measuredHeight, EXACTLY)
47             )
48         }
49     }
50 }
51