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 android.tools.flicker.rules
18 
19 import android.app.Instrumentation
20 import android.content.Context
21 import android.os.RemoteException
22 import android.tools.FLICKER_TAG
23 import android.tools.Rotation
24 import android.tools.traces.parsers.WindowManagerStateHelper
25 import android.tools.withTracing
26 import android.util.Log
27 import android.view.WindowManager
28 import androidx.test.platform.app.InstrumentationRegistry
29 import androidx.test.uiautomator.UiDevice
30 import org.junit.rules.TestWatcher
31 import org.junit.runner.Description
32 
33 /**
34  * Changes display orientation before a test
35  *
36  * @param targetOrientation Target orientation
37  * @param instrumentation Instrumentation mechanism to use
38  * @param clearCacheAfterParsing If the caching used while parsing the proto should be
39  *
40  * ```
41  *                               cleared or remain in memory
42  * ```
43  */
44 data class ChangeDisplayOrientationRule
45 @JvmOverloads
46 constructor(
47     private val targetOrientation: Rotation,
48     private val resetOrientationAfterTest: Boolean = true,
49     private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation(),
50     private val clearCacheAfterParsing: Boolean = true
51 ) : TestWatcher() {
52     private var initialOrientation = Rotation.ROTATION_0
53 
startingnull54     override fun starting(description: Description?) {
55         withTracing("ChangeDisplayOrientationRule:starting") {
56             Log.v(
57                 FLICKER_TAG,
58                 "Changing display orientation to " +
59                     "$targetOrientation ${targetOrientation.description}"
60             )
61             val wm =
62                 instrumentation.context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
63             initialOrientation = Rotation.getByValue(wm.defaultDisplay.rotation)
64             setRotation(targetOrientation, instrumentation, clearCacheAfterParsing)
65         }
66     }
67 
finishednull68     override fun finished(description: Description?) {
69         withTracing("ChangeDisplayOrientationRule:finished") {
70             if (resetOrientationAfterTest) {
71                 setRotation(initialOrientation, instrumentation, clearCacheAfterParsing)
72             }
73         }
74     }
75 
76     companion object {
77         @JvmOverloads
setRotationnull78         fun setRotation(
79             rotation: Rotation,
80             instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation(),
81             clearCacheAfterParsing: Boolean = true,
82             wmHelper: WindowManagerStateHelper =
83                 WindowManagerStateHelper(
84                     instrumentation,
85                     clearCacheAfterParsing = clearCacheAfterParsing
86                 )
87         ) {
88             val device: UiDevice = UiDevice.getInstance(instrumentation)
89 
90             try {
91                 when (rotation) {
92                     Rotation.ROTATION_270 -> device.setOrientationRight()
93                     Rotation.ROTATION_90 -> device.setOrientationLeft()
94                     Rotation.ROTATION_0 -> device.setOrientationNatural()
95                     else -> device.setOrientationNatural()
96                 }
97 
98                 if (wmHelper.currentState.wmState.canRotate) {
99                     wmHelper.StateSyncBuilder().withRotation(rotation).waitForAndVerify()
100                 } else {
101                     wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify()
102                     Log.v(FLICKER_TAG, "Rotation is not allowed in the state")
103                     return
104                 }
105                 device.freezeRotation()
106             } catch (e: RemoteException) {
107                 throw RuntimeException(e)
108             }
109         }
110     }
111 }
112