Loading packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt +6 −79 Original line number Diff line number Diff line Loading @@ -17,15 +17,11 @@ package com.android.systemui import android.content.Context import android.content.res.Resources import android.graphics.Path import android.graphics.Rect import android.graphics.RectF import android.hardware.camera2.CameraManager import android.util.PathParser import com.android.systemui.res.R import java.util.concurrent.Executor import kotlin.math.roundToInt /** * Listens for usage of the Camera and controls the ScreenDecorations transition to show extra Loading Loading @@ -163,89 +159,20 @@ class CameraAvailabilityListener( } companion object Factory { fun build(context: Context, executor: Executor): CameraAvailabilityListener { fun build( context: Context, executor: Executor, cameraProtectionLoader: CameraProtectionLoader ): CameraAvailabilityListener { val manager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager val res = context.resources val cameraProtectionInfoList = loadCameraProtectionInfoList(res) val cameraProtectionInfoList = cameraProtectionLoader.loadCameraProtectionInfoList() val excluded = res.getString(R.string.config_cameraProtectionExcludedPackages) return CameraAvailabilityListener(manager, cameraProtectionInfoList, excluded, executor) } private fun pathFromString(pathString: String): Path { val spec = pathString.trim() val p: Path try { p = PathParser.createPathFromPathData(spec) } catch (e: Throwable) { throw IllegalArgumentException("Invalid protection path", e) } return p } private fun loadCameraProtectionInfoList(res: Resources): List<CameraProtectionInfo> { val list = mutableListOf<CameraProtectionInfo>() val front = loadCameraProtectionInfo( res, R.string.config_protectedCameraId, R.string.config_protectedPhysicalCameraId, R.string.config_frontBuiltInDisplayCutoutProtection ) if (front != null) { list.add(front) } val inner = loadCameraProtectionInfo( res, R.string.config_protectedInnerCameraId, R.string.config_protectedInnerPhysicalCameraId, R.string.config_innerBuiltInDisplayCutoutProtection ) if (inner != null) { list.add(inner) } return list } private fun loadCameraProtectionInfo( res: Resources, cameraIdRes: Int, physicalCameraIdRes: Int, pathRes: Int ): CameraProtectionInfo? { val logicalCameraId = res.getString(cameraIdRes) if (logicalCameraId.isNullOrEmpty()) { return null } val physicalCameraId = res.getString(physicalCameraIdRes) val protectionPath = pathFromString(res.getString(pathRes)) val computed = RectF() protectionPath.computeBounds(computed) val protectionBounds = Rect( computed.left.roundToInt(), computed.top.roundToInt(), computed.right.roundToInt(), computed.bottom.roundToInt() ) return CameraProtectionInfo( logicalCameraId, physicalCameraId, protectionPath, protectionBounds ) } } data class CameraProtectionInfo( val logicalCameraId: String, val physicalCameraId: String?, val cutoutProtectionPath: Path, val cutoutBounds: Rect, ) private data class OpenCameraInfo( val logicalCameraId: String, val packageId: String, Loading packages/SystemUI/src/com/android/systemui/CameraProtectionInfo.kt 0 → 100644 +27 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui import android.graphics.Path import android.graphics.Rect data class CameraProtectionInfo( val logicalCameraId: String, val physicalCameraId: String?, val cutoutProtectionPath: Path, val cutoutBounds: Rect, ) packages/SystemUI/src/com/android/systemui/CameraProtectionLoader.kt 0 → 100644 +88 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui import android.content.Context import android.graphics.Path import android.graphics.Rect import android.graphics.RectF import android.util.PathParser import com.android.systemui.res.R import javax.inject.Inject import kotlin.math.roundToInt class CameraProtectionLoader @Inject constructor(private val context: Context) { fun loadCameraProtectionInfoList(): List<CameraProtectionInfo> { val list = mutableListOf<CameraProtectionInfo>() val front = loadCameraProtectionInfo( R.string.config_protectedCameraId, R.string.config_protectedPhysicalCameraId, R.string.config_frontBuiltInDisplayCutoutProtection ) if (front != null) { list.add(front) } val inner = loadCameraProtectionInfo( R.string.config_protectedInnerCameraId, R.string.config_protectedInnerPhysicalCameraId, R.string.config_innerBuiltInDisplayCutoutProtection ) if (inner != null) { list.add(inner) } return list } private fun loadCameraProtectionInfo( cameraIdRes: Int, physicalCameraIdRes: Int, pathRes: Int ): CameraProtectionInfo? { val logicalCameraId = context.getString(cameraIdRes) if (logicalCameraId.isNullOrEmpty()) { return null } val physicalCameraId = context.getString(physicalCameraIdRes) val protectionPath = pathFromString(context.getString(pathRes)) val computed = RectF() protectionPath.computeBounds(computed) val protectionBounds = Rect( computed.left.roundToInt(), computed.top.roundToInt(), computed.right.roundToInt(), computed.bottom.roundToInt() ) return CameraProtectionInfo( logicalCameraId, physicalCameraId, protectionPath, protectionBounds ) } private fun pathFromString(pathString: String): Path { return try { PathParser.createPathFromPathData(pathString.trim()) } catch (e: Throwable) { throw IllegalArgumentException("Invalid protection path", e) } } } packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +7 −2 Original line number Diff line number Diff line Loading @@ -146,6 +146,7 @@ public class ScreenDecorations implements private final ThreadFactory mThreadFactory; private final DecorProviderFactory mDotFactory; private final FaceScanningProviderFactory mFaceScanningFactory; private final CameraProtectionLoader mCameraProtectionLoader; public final int mFaceScanningViewId; @VisibleForTesting Loading Loading @@ -333,7 +334,8 @@ public class ScreenDecorations implements FaceScanningProviderFactory faceScanningFactory, ScreenDecorationsLogger logger, FacePropertyRepository facePropertyRepository, JavaAdapter javaAdapter) { JavaAdapter javaAdapter, CameraProtectionLoader cameraProtectionLoader) { mContext = context; mSecureSettings = secureSettings; mCommandRegistry = commandRegistry; Loading @@ -343,6 +345,7 @@ public class ScreenDecorations implements mThreadFactory = threadFactory; mDotFactory = dotFactory; mFaceScanningFactory = faceScanningFactory; mCameraProtectionLoader = cameraProtectionLoader; mFaceScanningViewId = com.android.systemui.res.R.id.face_scanning_anim; mLogger = logger; mFacePropertyRepository = facePropertyRepository; Loading Loading @@ -981,7 +984,9 @@ public class ScreenDecorations implements Resources res = mContext.getResources(); boolean enabled = res.getBoolean(R.bool.config_enableDisplayCutoutProtection); if (enabled) { mCameraListener = CameraAvailabilityListener.Factory.build(mContext, mExecutor); mCameraListener = CameraAvailabilityListener.Factory.build( mContext, mExecutor, mCameraProtectionLoader); mCameraListener.addTransitionCallback(mCameraTransitionCallback); mCameraListener.startListening(); } Loading packages/SystemUI/tests/src/com/android/systemui/CameraAvailabilityListenerTest.kt +9 −4 Original line number Diff line number Diff line Loading @@ -344,7 +344,12 @@ class CameraAvailabilityListenerTest : SysuiTestCase() { } private fun createAndStartSut(): CameraAvailabilityListener { return CameraAvailabilityListener.build(context, context.mainExecutor).also { return CameraAvailabilityListener.build( context, context.mainExecutor, CameraProtectionLoader((context)) ) .also { it.addTransitionCallback(cameraTransitionCallback) it.startListening() } Loading Loading
packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt +6 −79 Original line number Diff line number Diff line Loading @@ -17,15 +17,11 @@ package com.android.systemui import android.content.Context import android.content.res.Resources import android.graphics.Path import android.graphics.Rect import android.graphics.RectF import android.hardware.camera2.CameraManager import android.util.PathParser import com.android.systemui.res.R import java.util.concurrent.Executor import kotlin.math.roundToInt /** * Listens for usage of the Camera and controls the ScreenDecorations transition to show extra Loading Loading @@ -163,89 +159,20 @@ class CameraAvailabilityListener( } companion object Factory { fun build(context: Context, executor: Executor): CameraAvailabilityListener { fun build( context: Context, executor: Executor, cameraProtectionLoader: CameraProtectionLoader ): CameraAvailabilityListener { val manager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager val res = context.resources val cameraProtectionInfoList = loadCameraProtectionInfoList(res) val cameraProtectionInfoList = cameraProtectionLoader.loadCameraProtectionInfoList() val excluded = res.getString(R.string.config_cameraProtectionExcludedPackages) return CameraAvailabilityListener(manager, cameraProtectionInfoList, excluded, executor) } private fun pathFromString(pathString: String): Path { val spec = pathString.trim() val p: Path try { p = PathParser.createPathFromPathData(spec) } catch (e: Throwable) { throw IllegalArgumentException("Invalid protection path", e) } return p } private fun loadCameraProtectionInfoList(res: Resources): List<CameraProtectionInfo> { val list = mutableListOf<CameraProtectionInfo>() val front = loadCameraProtectionInfo( res, R.string.config_protectedCameraId, R.string.config_protectedPhysicalCameraId, R.string.config_frontBuiltInDisplayCutoutProtection ) if (front != null) { list.add(front) } val inner = loadCameraProtectionInfo( res, R.string.config_protectedInnerCameraId, R.string.config_protectedInnerPhysicalCameraId, R.string.config_innerBuiltInDisplayCutoutProtection ) if (inner != null) { list.add(inner) } return list } private fun loadCameraProtectionInfo( res: Resources, cameraIdRes: Int, physicalCameraIdRes: Int, pathRes: Int ): CameraProtectionInfo? { val logicalCameraId = res.getString(cameraIdRes) if (logicalCameraId.isNullOrEmpty()) { return null } val physicalCameraId = res.getString(physicalCameraIdRes) val protectionPath = pathFromString(res.getString(pathRes)) val computed = RectF() protectionPath.computeBounds(computed) val protectionBounds = Rect( computed.left.roundToInt(), computed.top.roundToInt(), computed.right.roundToInt(), computed.bottom.roundToInt() ) return CameraProtectionInfo( logicalCameraId, physicalCameraId, protectionPath, protectionBounds ) } } data class CameraProtectionInfo( val logicalCameraId: String, val physicalCameraId: String?, val cutoutProtectionPath: Path, val cutoutBounds: Rect, ) private data class OpenCameraInfo( val logicalCameraId: String, val packageId: String, Loading
packages/SystemUI/src/com/android/systemui/CameraProtectionInfo.kt 0 → 100644 +27 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui import android.graphics.Path import android.graphics.Rect data class CameraProtectionInfo( val logicalCameraId: String, val physicalCameraId: String?, val cutoutProtectionPath: Path, val cutoutBounds: Rect, )
packages/SystemUI/src/com/android/systemui/CameraProtectionLoader.kt 0 → 100644 +88 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui import android.content.Context import android.graphics.Path import android.graphics.Rect import android.graphics.RectF import android.util.PathParser import com.android.systemui.res.R import javax.inject.Inject import kotlin.math.roundToInt class CameraProtectionLoader @Inject constructor(private val context: Context) { fun loadCameraProtectionInfoList(): List<CameraProtectionInfo> { val list = mutableListOf<CameraProtectionInfo>() val front = loadCameraProtectionInfo( R.string.config_protectedCameraId, R.string.config_protectedPhysicalCameraId, R.string.config_frontBuiltInDisplayCutoutProtection ) if (front != null) { list.add(front) } val inner = loadCameraProtectionInfo( R.string.config_protectedInnerCameraId, R.string.config_protectedInnerPhysicalCameraId, R.string.config_innerBuiltInDisplayCutoutProtection ) if (inner != null) { list.add(inner) } return list } private fun loadCameraProtectionInfo( cameraIdRes: Int, physicalCameraIdRes: Int, pathRes: Int ): CameraProtectionInfo? { val logicalCameraId = context.getString(cameraIdRes) if (logicalCameraId.isNullOrEmpty()) { return null } val physicalCameraId = context.getString(physicalCameraIdRes) val protectionPath = pathFromString(context.getString(pathRes)) val computed = RectF() protectionPath.computeBounds(computed) val protectionBounds = Rect( computed.left.roundToInt(), computed.top.roundToInt(), computed.right.roundToInt(), computed.bottom.roundToInt() ) return CameraProtectionInfo( logicalCameraId, physicalCameraId, protectionPath, protectionBounds ) } private fun pathFromString(pathString: String): Path { return try { PathParser.createPathFromPathData(pathString.trim()) } catch (e: Throwable) { throw IllegalArgumentException("Invalid protection path", e) } } }
packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +7 −2 Original line number Diff line number Diff line Loading @@ -146,6 +146,7 @@ public class ScreenDecorations implements private final ThreadFactory mThreadFactory; private final DecorProviderFactory mDotFactory; private final FaceScanningProviderFactory mFaceScanningFactory; private final CameraProtectionLoader mCameraProtectionLoader; public final int mFaceScanningViewId; @VisibleForTesting Loading Loading @@ -333,7 +334,8 @@ public class ScreenDecorations implements FaceScanningProviderFactory faceScanningFactory, ScreenDecorationsLogger logger, FacePropertyRepository facePropertyRepository, JavaAdapter javaAdapter) { JavaAdapter javaAdapter, CameraProtectionLoader cameraProtectionLoader) { mContext = context; mSecureSettings = secureSettings; mCommandRegistry = commandRegistry; Loading @@ -343,6 +345,7 @@ public class ScreenDecorations implements mThreadFactory = threadFactory; mDotFactory = dotFactory; mFaceScanningFactory = faceScanningFactory; mCameraProtectionLoader = cameraProtectionLoader; mFaceScanningViewId = com.android.systemui.res.R.id.face_scanning_anim; mLogger = logger; mFacePropertyRepository = facePropertyRepository; Loading Loading @@ -981,7 +984,9 @@ public class ScreenDecorations implements Resources res = mContext.getResources(); boolean enabled = res.getBoolean(R.bool.config_enableDisplayCutoutProtection); if (enabled) { mCameraListener = CameraAvailabilityListener.Factory.build(mContext, mExecutor); mCameraListener = CameraAvailabilityListener.Factory.build( mContext, mExecutor, mCameraProtectionLoader); mCameraListener.addTransitionCallback(mCameraTransitionCallback); mCameraListener.startListening(); } Loading
packages/SystemUI/tests/src/com/android/systemui/CameraAvailabilityListenerTest.kt +9 −4 Original line number Diff line number Diff line Loading @@ -344,7 +344,12 @@ class CameraAvailabilityListenerTest : SysuiTestCase() { } private fun createAndStartSut(): CameraAvailabilityListener { return CameraAvailabilityListener.build(context, context.mainExecutor).also { return CameraAvailabilityListener.build( context, context.mainExecutor, CameraProtectionLoader((context)) ) .also { it.addTransitionCallback(cameraTransitionCallback) it.startListening() } Loading