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