1 /*
2  * Copyright (C) 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 com.android.settingslib.spa.screenshot.util
18 
19 import android.os.Build
20 import androidx.activity.ComponentActivity
21 import androidx.compose.material3.MaterialTheme
22 import androidx.compose.material3.Surface
23 import androidx.compose.runtime.Composable
24 import androidx.compose.ui.platform.ViewRootForTest
25 import androidx.compose.ui.test.junit4.createAndroidComposeRule
26 import androidx.compose.ui.test.onRoot
27 import com.android.settingslib.spa.framework.theme.SettingsTheme
28 import org.junit.rules.RuleChain
29 import org.junit.rules.TestRule
30 import org.junit.runner.Description
31 import org.junit.runners.model.Statement
32 import platform.test.screenshot.DeviceEmulationRule
33 import platform.test.screenshot.DeviceEmulationSpec
34 import platform.test.screenshot.MaterialYouColorsRule
35 import platform.test.screenshot.ScreenshotTestRule
36 import platform.test.screenshot.getEmulatedDevicePathConfig
37 
38 /** A rule for Settings screenshot diff tests. */
39 class SettingsScreenshotTestRule(
40     emulationSpec: DeviceEmulationSpec,
41     assetsPathRelativeToBuildRoot: String
42 ) : TestRule {
43     private val colorsRule = MaterialYouColorsRule()
44     private val deviceEmulationRule = DeviceEmulationRule(emulationSpec)
45     private val screenshotRule =
46         ScreenshotTestRule(
47             SettingsGoldenPathManager(
48                 getEmulatedDevicePathConfig(emulationSpec),
49                 assetsPathRelativeToBuildRoot
50             )
51         )
52     private val composeRule = createAndroidComposeRule<ComponentActivity>()
53     private val delegateRule =
54         RuleChain.outerRule(colorsRule)
55             .around(deviceEmulationRule)
56             .around(screenshotRule)
57             .around(composeRule)
58     private val matcher = UnitTestBitmapMatcher
59 
applynull60     override fun apply(base: Statement, description: Description): Statement {
61         return delegateRule.apply(base, description)
62     }
63 
64     /**
65      * Compare [content] with the golden image identified by [goldenIdentifier] in the context of
66      * [testSpec].
67      */
screenshotTestnull68     fun screenshotTest(
69         goldenIdentifier: String,
70         content: @Composable () -> Unit,
71     ) {
72         // Make sure that the activity draws full screen and fits the whole display.
73         val activity = composeRule.activity
74         activity.mainExecutor.execute { activity.window.setDecorFitsSystemWindows(false) }
75 
76         // Set the content using the AndroidComposeRule to make sure that the Activity is set up
77         // correctly.
78         composeRule.setContent {
79             SettingsTheme {
80                 Surface(
81                     color = MaterialTheme.colorScheme.background,
82                 ) {
83                     content()
84                 }
85             }
86         }
87         composeRule.waitForIdle()
88 
89         val view = (composeRule.onRoot().fetchSemanticsNode().root as ViewRootForTest).view
90         screenshotRule.assertBitmapAgainstGolden(view.drawIntoBitmap(), goldenIdentifier, matcher)
91     }
92 }
93 
94 /** Create a [SettingsScreenshotTestRule] for settings screenshot tests. */
settingsScreenshotTestRulenull95 fun settingsScreenshotTestRule(
96     emulationSpec: DeviceEmulationSpec,
97 ): SettingsScreenshotTestRule {
98     val assetPath = if (Build.FINGERPRINT.contains("robolectric")) {
99         "frameworks/base/packages/SettingsLib/Spa/screenshot/robotests/assets"
100     } else {
101         "frameworks/base/packages/SettingsLib/Spa/screenshot/assets"
102     }
103     return SettingsScreenshotTestRule(
104         emulationSpec,
105         assetPath
106     )
107 }
108