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.traces.surfaceflinger
18 
19 import android.graphics.Rect
20 import android.tools.Position
21 import android.tools.Rotation
22 import android.tools.datatypes.Size
23 import android.tools.traces.wm.DisplayContent
24 import android.tools.withCache
25 import kotlin.math.min
26 
27 /** Wrapper for DisplayProto (frameworks/native/services/surfaceflinger/layerproto/display.proto) */
28 class Display
29 private constructor(
30     val id: Long,
31     val name: String,
32     val layerStackId: Int,
33     val size: Size,
34     val layerStackSpace: Rect,
35     val transform: Transform,
36     val isVirtual: Boolean,
37     val dpiX: Double,
38     val dpiY: Double,
39 ) {
40     val isOff = layerStackId == BLANK_LAYER_STACK
41     val isOn = !isOff
42 
43     // Alias for layerStackSpace, since bounds is what is used for layers
44     val bounds = layerStackSpace
45 
navBarPositionnull46     fun navBarPosition(isGesturalNavigation: Boolean): Position {
47         val requestedRotation = transform.getRotation()
48 
49         return when {
50             // display off
51             isOff -> Position.INVALID
52             // nav bar is at the bottom of the screen
53             !requestedRotation.isRotated() || isGesturalNavigation -> Position.BOTTOM
54             // nav bar is on the right side
55             requestedRotation == Rotation.ROTATION_90 -> Position.RIGHT
56             // nav bar is on the left side
57             requestedRotation == Rotation.ROTATION_270 -> Position.LEFT
58             else -> error("Unknown rotation $requestedRotation")
59         }
60     }
61 
62     val isLargeScreen: Boolean
63         get() {
64             val dpi = dpiX.toInt()
65             val smallestWidth =
66                 DisplayContent.dpiFromPx(min(size.width.toFloat(), size.height.toFloat()), dpi)
67             return smallestWidth >= DisplayContent.TABLET_MIN_DPS
68         }
69 
equalsnull70     override fun equals(other: Any?): Boolean {
71         if (this === other) return true
72         if (other !is Display) return false
73 
74         if (id != other.id) return false
75         if (name != other.name) return false
76         if (layerStackId != other.layerStackId) return false
77         if (size != other.size) return false
78         if (layerStackSpace != other.layerStackSpace) return false
79         if (transform != other.transform) return false
80         if (isVirtual != other.isVirtual) return false
81 
82         return true
83     }
84 
hashCodenull85     override fun hashCode(): Int {
86         var result = id.hashCode()
87         result = 31 * result + name.hashCode()
88         result = 31 * result + layerStackId
89         result = 31 * result + size.hashCode()
90         result = 31 * result + layerStackSpace.hashCode()
91         result = 31 * result + transform.hashCode()
92         result = 31 * result + isVirtual.hashCode()
93         return result
94     }
95 
96     companion object {
97         const val BLANK_LAYER_STACK = -1
98 
99         val EMPTY: Display
<lambda>null100             get() = withCache {
101                 Display(
102                     id = 0,
103                     name = "EMPTY",
104                     layerStackId = BLANK_LAYER_STACK,
105                     size = Size.EMPTY,
106                     layerStackSpace = Rect(),
107                     transform = Transform.EMPTY,
108                     isVirtual = false,
109                     dpiX = 0.0,
110                     dpiY = 0.0,
111                 )
112             }
113 
fromnull114         fun from(
115             id: Long,
116             name: String,
117             layerStackId: Int,
118             size: Size,
119             layerStackSpace: Rect,
120             transform: Transform,
121             isVirtual: Boolean,
122             dpiX: Double,
123             dpiY: Double,
124         ): Display = withCache {
125             Display(id, name, layerStackId, size, layerStackSpace, transform, isVirtual, dpiX, dpiY)
126         }
127     }
128 }
129