1 /*
2  * Copyright 2022 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 androidx.graphics.lowlatency
18 
19 import android.graphics.Matrix
20 import android.os.Build
21 import android.util.Log
22 import android.view.Surface
23 import android.view.View
24 import androidx.annotation.RequiresApi
25 import androidx.graphics.surface.JniBindings
26 import androidx.graphics.surface.SurfaceControlCompat
27 
28 /**
29  * Helper class to determine the corresponding transformation hint based on various Android API
30  * levels
31  */
32 internal class BufferTransformHintResolver {
33 
getBufferTransformHintnull34     fun getBufferTransformHint(view: View): Int {
35         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S_V2) {
36             return TransformHintHelper.resolveBufferTransformHint(view)
37         } else {
38             val orientation: String?
39             return try {
40                 orientation = JniBindings.nGetDisplayOrientation()
41                 val rotation = view.display?.rotation
42                 if (rotation != null) {
43                     val transform =
44                         getBufferTransformHintFromInstallOrientation(orientation, rotation)
45                     Log.v(TAG, "Obtained transform: $transform for orientation: $orientation")
46                     transform
47                 } else {
48                     Log.w(TAG, "Unable to obtain current display rotation")
49                     UNKNOWN_TRANSFORM
50                 }
51             } catch (exception: Exception) {
52                 Log.w(TAG, "Unable to obtain current display orientation")
53                 UNKNOWN_TRANSFORM
54             }
55         }
56     }
57 
getBufferTransformHintFromInstallOrientationnull58     internal fun getBufferTransformHintFromInstallOrientation(
59         orientation: String,
60         rotation: Int
61     ): Int =
62         when (orientation) {
63             ORIENTATION_90 -> {
64                 when (rotation) {
65                     Surface.ROTATION_0 -> SurfaceControlCompat.BUFFER_TRANSFORM_ROTATE_90
66                     Surface.ROTATION_90 -> SurfaceControlCompat.BUFFER_TRANSFORM_ROTATE_180
67                     Surface.ROTATION_180 -> SurfaceControlCompat.BUFFER_TRANSFORM_ROTATE_270
68                     Surface.ROTATION_270 -> SurfaceControlCompat.BUFFER_TRANSFORM_IDENTITY
69                     else -> UNKNOWN_TRANSFORM
70                 }
71             }
72             ORIENTATION_180 -> {
73                 when (rotation) {
74                     Surface.ROTATION_0 -> SurfaceControlCompat.BUFFER_TRANSFORM_ROTATE_180
75                     Surface.ROTATION_90 -> SurfaceControlCompat.BUFFER_TRANSFORM_ROTATE_270
76                     Surface.ROTATION_180 -> SurfaceControlCompat.BUFFER_TRANSFORM_IDENTITY
77                     Surface.ROTATION_270 -> SurfaceControlCompat.BUFFER_TRANSFORM_ROTATE_90
78                     else -> UNKNOWN_TRANSFORM
79                 }
80             }
81             ORIENTATION_270 -> {
82                 when (rotation) {
83                     Surface.ROTATION_0 -> SurfaceControlCompat.BUFFER_TRANSFORM_ROTATE_270
84                     Surface.ROTATION_90 -> SurfaceControlCompat.BUFFER_TRANSFORM_IDENTITY
85                     Surface.ROTATION_180 -> SurfaceControlCompat.BUFFER_TRANSFORM_ROTATE_90
86                     Surface.ROTATION_270 -> SurfaceControlCompat.BUFFER_TRANSFORM_ROTATE_180
87                     else -> UNKNOWN_TRANSFORM
88                 }
89             }
90             ORIENTATION_0 -> {
91                 when (rotation) {
92                     Surface.ROTATION_0 -> SurfaceControlCompat.BUFFER_TRANSFORM_IDENTITY
93                     Surface.ROTATION_90 -> SurfaceControlCompat.BUFFER_TRANSFORM_ROTATE_90
94                     Surface.ROTATION_180 -> SurfaceControlCompat.BUFFER_TRANSFORM_ROTATE_180
95                     Surface.ROTATION_270 -> SurfaceControlCompat.BUFFER_TRANSFORM_ROTATE_270
96                     else -> UNKNOWN_TRANSFORM
97                 }
98             }
99             else -> {
100                 Log.w(TAG, "Unknown orientation \"$orientation\"")
101                 UNKNOWN_TRANSFORM
102             }
103         }
104 
105     internal companion object {
106 
107         const val TAG = "TRANSFORM_HINT_RESOLVER"
108 
109         const val UNKNOWN_TRANSFORM = -1
110 
111         const val ORIENTATION_0 = "ORIENTATION_0"
112         const val ORIENTATION_90 = "ORIENTATION_90"
113         const val ORIENTATION_180 = "ORIENTATION_180"
114         const val ORIENTATION_270 = "ORIENTATION_270"
115 
116         @RequiresApi(Build.VERSION_CODES.Q)
configureTransformMatrixnull117         internal fun configureTransformMatrix(
118             matrix: Matrix,
119             width: Float,
120             height: Float,
121             @SurfaceControlCompat.Companion.BufferTransform transform: Int
122         ): Matrix =
123             matrix.apply {
124                 when (transform) {
125                     SurfaceControlCompat.BUFFER_TRANSFORM_ROTATE_90 -> {
126                         reset()
127                         setRotate(90f)
128                         postTranslate(width, 0f)
129                     }
130                     SurfaceControlCompat.BUFFER_TRANSFORM_ROTATE_180 -> {
131                         reset()
132                         setRotate(180f)
133                         postTranslate(width, height)
134                     }
135                     SurfaceControlCompat.BUFFER_TRANSFORM_ROTATE_270 -> {
136                         reset()
137                         setRotate(270f)
138                         postTranslate(0f, height)
139                     }
140                     else -> {
141                         reset()
142                     }
143                 }
144             }
145     }
146 }
147 
148 /** Helper class to avoid class verification errors */
149 @RequiresApi(Build.VERSION_CODES.S_V2)
150 internal class TransformHintHelper private constructor() {
151 
152     companion object {
153         @RequiresApi(Build.VERSION_CODES.S_V2)
resolveBufferTransformHintnull154         fun resolveBufferTransformHint(view: View): Int =
155             view.rootSurfaceControl?.bufferTransformHint ?: 0
156     }
157 }
158