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.wm.shell.flicker.appcompat
18 
19 import android.app.Instrumentation
20 import android.system.helpers.CommandsHelper
21 import androidx.test.platform.app.InstrumentationRegistry
22 import org.junit.rules.TestRule
23 import org.junit.runner.Description
24 import org.junit.runners.model.Statement
25 
26 /**
27  * JUnit Rule to handle letterboxStyles and states
28  */
29 class LetterboxRule(
30         private val withLetterboxEducationEnabled: Boolean = false,
31         private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation(),
32         private val cmdHelper: CommandsHelper = CommandsHelper.getInstance(instrumentation)
33 ) : TestRule {
34 
35     private val execAdb: (String) -> String = {cmd -> cmdHelper.executeShellCommand(cmd)}
36     private lateinit var _letterboxStyle: MutableMap<String, String>
37 
38     val letterboxStyle: Map<String, String>
39         get() {
40             if (!::_letterboxStyle.isInitialized) {
41                 _letterboxStyle = mapLetterboxStyle()
42             }
43             return _letterboxStyle
44         }
45 
46     val cornerRadius: Int?
47         get() = asInt(letterboxStyle["Corner radius"])
48 
49     val hasCornerRadius: Boolean
50         get() {
51             val radius = cornerRadius
52             return radius != null && radius > 0
53         }
54 
55     val isIgnoreOrientationRequest: Boolean
56         get() = execAdb("wm get-ignore-orientation-request")?.contains("true") ?: false
57 
58     override fun apply(base: Statement?, description: Description?): Statement {
59         resetLetterboxStyle()
60         _letterboxStyle = mapLetterboxStyle()
61         val isLetterboxEducationEnabled = _letterboxStyle.getValue("Is education enabled")
62         var hasLetterboxEducationStateChanged = false
63         if ("$withLetterboxEducationEnabled" != isLetterboxEducationEnabled) {
64             hasLetterboxEducationStateChanged = true
65             execAdb("wm set-letterbox-style --isEducationEnabled " +
66                     withLetterboxEducationEnabled)
67         }
68         return try {
69             object : Statement() {
70                 @Throws(Throwable::class)
71                 override fun evaluate() {
72                     base!!.evaluate()
73                 }
74             }
75         } finally {
76             if (hasLetterboxEducationStateChanged) {
77                 execAdb("wm set-letterbox-style --isEducationEnabled " +
78                         isLetterboxEducationEnabled
79                 )
80             }
81             resetLetterboxStyle()
82         }
83     }
84 
85     private fun mapLetterboxStyle(): HashMap<String, String> {
86         val res = execAdb("wm get-letterbox-style")
87         val lines = res.lines()
88         val map = HashMap<String, String>()
89         for (line in lines) {
90             val keyValuePair = line.split(":")
91             if (keyValuePair.size == 2) {
92                 val key = keyValuePair[0].trim()
93                 map[key] = keyValuePair[1].trim()
94             }
95         }
96         return map
97     }
98 
99     private fun resetLetterboxStyle() {
100         execAdb("wm reset-letterbox-style")
101     }
102 
103     private fun asInt(str: String?): Int? = try {
104         str?.toInt()
105     } catch (e: NumberFormatException) {
106         null
107     }
108 }