1 /* 2 * Copyright (C) 2024 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.systemui 18 19 import android.content.Context 20 import android.graphics.Rect 21 import android.util.RotationUtils 22 import android.view.Display 23 import android.view.DisplayCutout 24 import com.android.systemui.display.naturalBounds 25 import dagger.assisted.Assisted 26 import dagger.assisted.AssistedFactory 27 import dagger.assisted.AssistedInject 28 29 interface SysUICutoutProvider { 30 31 /** 32 * Returns the [SysUICutoutInformation] for the current display and the current rotation. 33 * 34 * This means that the bounds of the display cutout and the camera protection will be 35 * adjusted/rotated for the current rotation. 36 */ cutoutInfoForCurrentDisplayAndRotationnull37 fun cutoutInfoForCurrentDisplayAndRotation(): SysUICutoutInformation? 38 } 39 40 class SysUICutoutProviderImpl 41 @AssistedInject 42 constructor( 43 @Assisted private val context: Context, 44 @Assisted private val cameraProtectionLoader: CameraProtectionLoader, 45 ) : SysUICutoutProvider { 46 47 private val cameraProtectionList by lazy { 48 cameraProtectionLoader.loadCameraProtectionInfoList() 49 } 50 51 override fun cutoutInfoForCurrentDisplayAndRotation(): SysUICutoutInformation? { 52 val display = context.display 53 val displayCutout: DisplayCutout = display.cutout ?: return null 54 return SysUICutoutInformation(displayCutout, getCameraProtectionForDisplay(display)) 55 } 56 57 private fun getCameraProtectionForDisplay(display: Display): CameraProtectionInfo? { 58 val displayUniqueId: String? = display.uniqueId 59 if (displayUniqueId.isNullOrEmpty()) { 60 return null 61 } 62 val cameraProtection: CameraProtectionInfo = 63 cameraProtectionList.firstOrNull { it.displayUniqueId == displayUniqueId } 64 ?: return null 65 val adjustedBoundsForRotation = 66 calculateCameraProtectionBoundsForRotation(display, cameraProtection.bounds) 67 return cameraProtection.copy(bounds = adjustedBoundsForRotation) 68 } 69 70 private fun calculateCameraProtectionBoundsForRotation( 71 display: Display, 72 originalProtectionBounds: Rect, 73 ): Rect { 74 val displayNaturalBounds = display.naturalBounds 75 val rotatedBoundsOut = Rect(originalProtectionBounds) 76 RotationUtils.rotateBounds( 77 /* inOutBounds = */ rotatedBoundsOut, 78 /* parentWidth = */ displayNaturalBounds.width(), 79 /* parentHeight = */ displayNaturalBounds.height(), 80 /* rotation = */ display.rotation, 81 ) 82 return rotatedBoundsOut 83 } 84 85 @AssistedFactory 86 interface Factory { 87 fun create( 88 context: Context, 89 cameraProtectionLoader: CameraProtectionLoader, 90 ): SysUICutoutProviderImpl 91 } 92 } 93