1 /*
2  * Copyright (C) 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 com.android.systemui.util
18 
19 import android.content.Context
20 import android.util.AttributeSet
21 import android.view.Choreographer
22 import androidx.constraintlayout.motion.widget.MotionLayout
23 
24 /**
25  * [MotionLayout] that avoids remeasuring with the same inputs in the same frame.
26  *
27  * This is important when this view is the child of a view that performs more than one measure pass
28  * (e.g. [LinearLayout] or [ConstraintLayout]). In those cases, if this view is measured with the
29  * same inputs in the same frame, we use the last result.
30  */
31 class NoRemeasureMotionLayout @JvmOverloads constructor(
32     context: Context,
33     attrs: AttributeSet?,
34     defStyle: Int = 0
35 ) : MotionLayout(context, attrs, defStyle) {
36 
37     private var lastWidthSpec: Int? = null
38     private var lastHeightSpec: Int? = null
39     private var lastFrame: Long? = null
40 
41     override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
42         if (
43             lastWidthSpec == widthMeasureSpec &&
44             lastHeightSpec == heightMeasureSpec &&
45             Choreographer.getMainThreadInstance()?.frameTime == lastFrame
46         ) {
47             setMeasuredDimension(measuredWidth, measuredHeight)
48             return
49         }
50         traceSection("NoRemeasureMotionLayout - measure") {
51             super.onMeasure(widthMeasureSpec, heightMeasureSpec)
52             lastWidthSpec = widthMeasureSpec
53             lastHeightSpec = heightMeasureSpec
54             lastFrame = Choreographer.getMainThreadInstance()?.frameTime
55         }
56     }
57 }
58