• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2024 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 android.input.cts_root
18 
19 import android.cts.input.EventVerifier
20 import android.graphics.Bitmap
21 import android.graphics.Color
22 import android.os.SystemProperties
23 import android.view.MotionEvent
24 import android.view.WindowManager
25 import android.virtualdevice.cts.common.VirtualDeviceRule
26 import androidx.test.filters.MediumTest
27 import androidx.test.platform.app.InstrumentationRegistry
28 import com.android.cts.input.CaptureEventActivity
29 import com.android.cts.input.DefaultPointerSpeedRule
30 import com.android.cts.input.TestPointerDevice
31 import com.android.cts.input.VirtualDisplayActivityScenario
32 import com.android.cts.input.inputeventmatchers.withMotionAction
33 import com.android.xts.root.annotations.RequireAdbRoot
34 import org.junit.After
35 import org.junit.Before
36 import org.junit.Ignore
37 import org.junit.Rule
38 import org.junit.Test
39 import org.junit.rules.TestName
40 import org.junit.runner.RunWith
41 import org.junit.runners.Parameterized
42 import org.junit.runners.Parameterized.Parameter
43 import platform.test.screenshot.GoldenPathManager
44 import platform.test.screenshot.PathConfig
45 import platform.test.screenshot.ScreenshotTestRule
46 import platform.test.screenshot.assertAgainstGolden
47 import platform.test.screenshot.matchers.AlmostPerfectMatcher
48 import platform.test.screenshot.matchers.BitmapMatcher
49 import kotlin.test.assertNotNull
50 
51 /**
52  * End-to-end tests for the hiding pointer icons of screenshots of secure displays
53  *
54  * We use a secure virtual display to launch the test activity, and use virtual Input devices to
55  * move the pointer for it to show up. We then take a screenshot of the display to ensure the icon
56  * does not shows up on screenshot. We use the virtual display to be able to precisely compare the
57  * screenshots across devices of various form factors and sizes.
58  *
59  * Following tests must be run as root as they require CAPTURE_SECURE_VIDEO_OUTPUT permission
60  * override which can only be done by root.
61  */
62 @MediumTest
63 @RunWith(Parameterized::class)
64 @RequireAdbRoot
65 class HidePointerIconOnSecureWindowScreenshotTest {
66     private lateinit var activity: CaptureEventActivity
67     private lateinit var verifier: EventVerifier
68     private lateinit var exactScreenshotMatcher: BitmapMatcher
69 
70     @get:Rule
71     val testName = TestName()
72     @get:Rule
73     val virtualDeviceRule = VirtualDeviceRule.createDefault()!!
74     // TODO(b/366492484): Remove reliance on VDM.
75     @get:Rule
76     val virtualDisplayRule = VirtualDisplayActivityScenario.Rule<CaptureEventActivity>(
77         testName,
78         useSecureDisplay = true,
79         virtualDeviceRule = virtualDeviceRule
80     )
81     @get:Rule
82     val defaultPointerSpeedRule = DefaultPointerSpeedRule()
83     @get:Rule
84     val screenshotRule = ScreenshotTestRule(GoldenPathManager(
85         InstrumentationRegistry.getInstrumentation().context,
86         ASSETS_PATH,
87         TEST_OUTPUT_PATH,
88         PathConfig()
89     ), disableIconPool = false)
90 
91     @Parameter(0)
92     lateinit var device: TestPointerDevice
93 
94     @Before
setUpnull95     fun setUp() {
96         activity = virtualDisplayRule.activity
97         activity.runOnUiThread {
98             activity.actionBar?.hide()
99             activity.window.decorView.rootView.setBackgroundColor(Color.WHITE)
100             activity.window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
101         }
102 
103         device.setUp(
104             virtualDeviceRule.defaultVirtualDevice,
105             virtualDisplayRule.virtualDisplay.display,
106         )
107 
108         verifier = EventVerifier(activity::getInputEvent)
109 
110         exactScreenshotMatcher =
111             AlmostPerfectMatcher(acceptableThresholdCount = MAX_PIXELS_DIFFERENT)
112     }
113 
114     @After
tearDownnull115     fun tearDown() {
116         device.tearDown()
117     }
118 
119     @Ignore("b/366475909")
120     @Test
testHidePointerIconOnSecureWindowScreenshotnull121     fun testHidePointerIconOnSecureWindowScreenshot() {
122         device.hoverMove(1, 1)
123         verifier.assertReceivedMotion(withMotionAction(MotionEvent.ACTION_HOVER_ENTER))
124         waitForPointerIconUpdate()
125 
126         assertScreenshotsMatch()
127     }
128 
getActualScreenshotnull129     private fun getActualScreenshot(): Bitmap {
130         val actualBitmap: Bitmap? = virtualDisplayRule.getScreenshot()
131         assertNotNull(actualBitmap, "Screenshot is null.")
132         return actualBitmap
133     }
134 
assertScreenshotsMatchnull135     private fun assertScreenshotsMatch() {
136         getActualScreenshot().assertAgainstGolden(
137             screenshotRule,
138             getParameterizedExpectedScreenshotName(),
139             exactScreenshotMatcher
140         )
141     }
142 
getParameterizedExpectedScreenshotNamenull143     private fun getParameterizedExpectedScreenshotName(): String {
144         // Replace illegal characters '[' and ']' in expected screenshot name with underscores.
145         return "${testName.methodName}expected".replace("""\[|\]""".toRegex(), "_")
146     }
147 
148     // We don't have a way to synchronously know when the requested pointer icon has been drawn
149     // to the display, so wait some time (at least one display frame) for the icon to propagate.
waitForPointerIconUpdatenull150     private fun waitForPointerIconUpdate() = Thread.sleep(500L * HW_TIMEOUT_MULTIPLIER)
151 
152     companion object {
153         const val MAX_PIXELS_DIFFERENT = 5
154         const val ASSETS_PATH = "tests/input/assets"
155         val TEST_OUTPUT_PATH =
156             "/sdcard/Download/CtsInputRootTestCases/" +
157             HidePointerIconOnSecureWindowScreenshotTest::class.java.simpleName
158         val HW_TIMEOUT_MULTIPLIER = SystemProperties.getInt("ro.hw_timeout_multiplier", 1);
159 
160         @JvmStatic
161         @Parameterized.Parameters(name = "{0}")
162         fun data(): Iterable<Any> =
163             listOf(TestPointerDevice.MOUSE, TestPointerDevice.DRAWING_TABLET)
164     }
165 }
166