1 /* 2 * Copyright 2023 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.material3.benchmark 18 19 import androidx.compose.material3.ExperimentalMaterial3Api 20 import androidx.compose.material3.MaterialTheme 21 import androidx.compose.material3.PlainTooltip 22 import androidx.compose.material3.RichTooltip 23 import androidx.compose.material3.Text 24 import androidx.compose.material3.TextButton 25 import androidx.compose.material3.TooltipBox 26 import androidx.compose.material3.TooltipDefaults 27 import androidx.compose.material3.TooltipScope 28 import androidx.compose.material3.TooltipState 29 import androidx.compose.material3.rememberTooltipState 30 import androidx.compose.runtime.Composable 31 import androidx.compose.runtime.rememberCoroutineScope 32 import androidx.compose.testutils.LayeredComposeTestCase 33 import androidx.compose.testutils.ToggleableTestCase 34 import androidx.compose.testutils.benchmark.ComposeBenchmarkRule 35 import androidx.compose.testutils.benchmark.benchmarkToFirstPixel 36 import androidx.compose.testutils.benchmark.toggleStateBenchmarkComposeMeasureLayout 37 import androidx.compose.ui.window.PopupPositionProvider 38 import kotlinx.coroutines.CoroutineScope 39 import kotlinx.coroutines.launch 40 import org.junit.Rule 41 import org.junit.Test 42 43 class TooltipBenchmark { 44 @get:Rule val benchmarkRule = ComposeBenchmarkRule() 45 <lambda>null46 private val plainTooltipTestCaseFactory = { TooltipTestCase(TooltipType.Plain) } <lambda>null47 private val richTooltipTestCaseFactory = { TooltipTestCase(TooltipType.Rich) } 48 49 @Test plainTooltipFirstPixelnull50 fun plainTooltipFirstPixel() { 51 benchmarkRule.benchmarkToFirstPixel(plainTooltipTestCaseFactory) 52 } 53 54 @Test richTooltipFirstPixelnull55 fun richTooltipFirstPixel() { 56 benchmarkRule.benchmarkToFirstPixel(richTooltipTestCaseFactory) 57 } 58 59 @Test plainTooltipVisibilityTestnull60 fun plainTooltipVisibilityTest() { 61 benchmarkRule.toggleStateBenchmarkComposeMeasureLayout( 62 caseFactory = plainTooltipTestCaseFactory, 63 assertOneRecomposition = false 64 ) 65 } 66 67 @Test richTooltipVisibilityTestnull68 fun richTooltipVisibilityTest() { 69 benchmarkRule.toggleStateBenchmarkComposeMeasureLayout( 70 caseFactory = richTooltipTestCaseFactory, 71 assertOneRecomposition = false 72 ) 73 } 74 } 75 76 @OptIn(ExperimentalMaterial3Api::class) 77 private class TooltipTestCase(val tooltipType: TooltipType) : 78 LayeredComposeTestCase(), ToggleableTestCase { 79 private lateinit var state: TooltipState 80 private lateinit var scope: CoroutineScope 81 82 @Composable MeasuredContentnull83 override fun MeasuredContent() { 84 state = rememberTooltipState() 85 scope = rememberCoroutineScope() 86 87 val tooltip: @Composable TooltipScope.() -> Unit 88 val positionProvider: PopupPositionProvider 89 when (tooltipType) { 90 TooltipType.Plain -> { 91 tooltip = { PlainTooltipTest() } 92 positionProvider = TooltipDefaults.rememberTooltipPositionProvider() 93 } 94 TooltipType.Rich -> { 95 tooltip = { RichTooltipTest() } 96 positionProvider = TooltipDefaults.rememberTooltipPositionProvider() 97 } 98 } 99 100 TooltipBox(positionProvider = positionProvider, tooltip = tooltip, state = state) {} 101 } 102 103 @Composable 104 override fun ContentWrappers(content: @Composable () -> Unit) { <lambda>null105 MaterialTheme { content() } 106 } 107 toggleStatenull108 override fun toggleState() { 109 if (state.isVisible) { 110 state.dismiss() 111 } else { 112 scope.launch { state.show() } 113 } 114 } 115 116 @Composable TooltipScopenull117 private fun TooltipScope.PlainTooltipTest() { 118 PlainTooltip { Text("Text") } 119 } 120 121 @Composable TooltipScopenull122 private fun TooltipScope.RichTooltipTest() { 123 RichTooltip( 124 title = { Text("Subhead") }, 125 action = { TextButton(onClick = {}) { Text(text = "Action") } } 126 ) { 127 Text(text = "Text") 128 } 129 } 130 } 131 132 private enum class TooltipType { 133 Plain, 134 Rich 135 } 136