Loading services/core/java/com/android/server/wm/AppCompatCameraPolicy.java +10 −4 Original line number Diff line number Diff line Loading @@ -58,14 +58,20 @@ class AppCompatCameraPolicy { DesktopModeFlags.ENABLE_CAMERA_COMPAT_SIMULATE_REQUESTED_ORIENTATION.isTrue() && DesktopModeHelper.canEnterDesktopMode(wmService.mContext); if (needsDisplayRotationCompatPolicy || needsCameraCompatFreeformPolicy) { mCameraStateMonitor = new CameraStateMonitor(displayContent, wmService.mH); final AppCompatCameraStateSource cameraStateListenerDelegate = new AppCompatCameraStateSource(); mCameraStateMonitor = new CameraStateMonitor(displayContent, wmService.mH, cameraStateListenerDelegate); mActivityRefresher = new ActivityRefresher(wmService, wmService.mH); mDisplayRotationCompatPolicy = needsDisplayRotationCompatPolicy ? new DisplayRotationCompatPolicy( displayContent, mCameraStateMonitor, mActivityRefresher) : null; displayContent, mCameraStateMonitor, cameraStateListenerDelegate, mActivityRefresher) : null; mCameraCompatFreeformPolicy = needsCameraCompatFreeformPolicy ? new CameraCompatFreeformPolicy(displayContent, mCameraStateMonitor, mActivityRefresher) : null; mCameraStateMonitor, cameraStateListenerDelegate, mActivityRefresher) : null; } else { mDisplayRotationCompatPolicy = null; mCameraCompatFreeformPolicy = null; Loading Loading @@ -158,7 +164,7 @@ class AppCompatCameraPolicy { mCameraCompatFreeformPolicy.dispose(); } if (mCameraStateMonitor != null) { mCameraStateMonitor.dispose(); mCameraStateMonitor.stopListeningToCameraState(); } } Loading services/core/java/com/android/server/wm/AppCompatCameraStatePolicy.java 0 → 100644 +44 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.server.wm; import android.annotation.NonNull; /** * Interface that camera compat policies to implement to be notified of camera open/close signals. */ interface AppCompatCameraStatePolicy { /** * Notifies the compat listener that a task has opened camera. */ void onCameraOpened(@NonNull ActivityRecord cameraActivity); /** * Checks whether a listener is ready to do a cleanup when camera is closed. * * <p>The notifier might try again if false is returned. */ // TODO(b/336474959): try to decouple `cameraId` from the listeners, as the treatment does not // change based on the cameraId - CameraStateMonitor should keep track of this. // This method actually checks "did an activity only temporarily close the camera", because a // refresh for compatibility is triggered. boolean canCameraBeClosed(@NonNull String cameraId); /** * Notifies the compat listener that camera is closed. */ void onCameraClosed(); } services/core/java/com/android/server/wm/AppCompatCameraStateSource.java 0 → 100644 +65 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.server.wm; import androidx.annotation.NonNull; import java.util.ArrayList; /** * Adapter for camera state updates, which notifies all camera policies of camera state changes. */ class AppCompatCameraStateSource implements AppCompatCameraStatePolicy { private final ArrayList<AppCompatCameraStatePolicy> mCameraStatePolicies = new ArrayList<>(); /** Adds a policy to notify when camera is opened and closed. */ public void addCameraStatePolicy(@NonNull AppCompatCameraStatePolicy policy) { mCameraStatePolicies.add(policy); } /** Removes a policy to notify about camera opened/closed signals. */ public void removeCameraStatePolicy(@NonNull AppCompatCameraStatePolicy policy) { mCameraStatePolicies.remove(policy); } @Override public void onCameraOpened(@NonNull ActivityRecord cameraActivity) { for (int i = 0; i < mCameraStatePolicies.size(); i++) { mCameraStatePolicies.get(i).onCameraOpened(cameraActivity); } } /** * @return {@code false} if any listener has reported that they cannot process camera close now. */ @Override public boolean canCameraBeClosed(@NonNull String cameraId) { for (int i = 0; i < mCameraStatePolicies.size(); i++) { if (!mCameraStatePolicies.get(i).canCameraBeClosed(cameraId)) { return false; } } return true; } @Override public void onCameraClosed() { for (int i = 0; i < mCameraStatePolicies.size(); i++) { mCameraStatePolicies.get(i).onCameraClosed(); } } } services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java +7 −3 Original line number Diff line number Diff line Loading @@ -58,7 +58,7 @@ import com.android.internal.protolog.WmProtoLogGroups; * changes to the camera and display orientation signals to match those expected on a portrait * device in that orientation (for example, on a standard phone). */ final class CameraCompatFreeformPolicy implements CameraStateMonitor.CameraCompatStateListener, final class CameraCompatFreeformPolicy implements AppCompatCameraStatePolicy, ActivityRefresher.Evaluator { private static final String TAG = TAG_WITH_CLASS_NAME ? "CameraCompatFreeformPolicy" : TAG_WM; Loading @@ -67,6 +67,8 @@ final class CameraCompatFreeformPolicy implements CameraStateMonitor.CameraCompa @NonNull private final ActivityRefresher mActivityRefresher; @NonNull private final AppCompatCameraStateSource mCameraStateNotifier; @NonNull private final CameraStateMonitor mCameraStateMonitor; // TODO(b/380840084): Consider moving this to the CameraStateMonitor, and keeping track of Loading @@ -82,14 +84,16 @@ final class CameraCompatFreeformPolicy implements CameraStateMonitor.CameraCompa CameraCompatFreeformPolicy(@NonNull DisplayContent displayContent, @NonNull CameraStateMonitor cameraStateMonitor, @NonNull AppCompatCameraStateSource cameraStateNotifier, @NonNull ActivityRefresher activityRefresher) { mDisplayContent = displayContent; mCameraStateMonitor = cameraStateMonitor; mCameraStateNotifier = cameraStateNotifier; mActivityRefresher = activityRefresher; } void start() { mCameraStateMonitor.addCameraStateListener(this); mCameraStateNotifier.addCameraStatePolicy(this); mActivityRefresher.addEvaluator(this); mIsRunning = true; } Loading @@ -101,7 +105,7 @@ final class CameraCompatFreeformPolicy implements CameraStateMonitor.CameraCompa /** Releases camera callback listener. */ void dispose() { mCameraStateMonitor.removeCameraStateListener(this); mCameraStateNotifier.removeCameraStatePolicy(this); mActivityRefresher.removeEvaluator(this); mIsRunning = false; } Loading services/core/java/com/android/server/wm/CameraStateMonitor.java +21 −65 Original line number Diff line number Diff line Loading @@ -76,13 +76,14 @@ class CameraStateMonitor { // TODO(b/336474959): should/can this go in the compat listeners? private final Set<String> mScheduledCompatModeUpdateCameraIdSet = new ArraySet<>(); private final ArrayList<CameraCompatStateListener> mCameraStateListeners = new ArrayList<>(); @VisibleForTesting final AppCompatCameraStatePolicy mAppCompatCameraStatePolicy; /** * Value toggled on {@link #startListeningToCameraState()} to {@code true} and on {@link * #dispose()} to {@code false}. * #stopListeningToCameraState()} to {@code false}. */ private boolean mIsRunning; private boolean mIsListeningToCameraState; private final CameraManager.AvailabilityCallback mAvailabilityCallback = new CameraManager.AvailabilityCallback() { Loading @@ -100,42 +101,41 @@ class CameraStateMonitor { } }; CameraStateMonitor(@NonNull DisplayContent displayContent, @NonNull Handler handler) { CameraStateMonitor(@NonNull DisplayContent displayContent, @NonNull Handler handler, @NonNull AppCompatCameraStatePolicy appCompatCameraStatePolicy) { // This constructor is called from DisplayContent constructor. Don't use any fields in // DisplayContent here since they aren't guaranteed to be set. mHandler = handler; mDisplayContent = displayContent; mAppCompatCameraStatePolicy = appCompatCameraStatePolicy; mWmService = displayContent.mWmService; mCameraManager = mWmService.mContext.getSystemService(CameraManager.class); } /** Starts listening to camera opened/closed signals. */ void startListeningToCameraState() { if (mCameraManager != null) { mCameraManager.registerAvailabilityCallback( mWmService.mContext.getMainExecutor(), mAvailabilityCallback); } mIsRunning = true; mIsListeningToCameraState = true; } /** Releases camera callback listener. */ void dispose() { /** Stops listening to camera opened/closed signals. */ public void stopListeningToCameraState() { if (mCameraManager != null) { mCameraManager.unregisterAvailabilityCallback(mAvailabilityCallback); } mIsRunning = false; mIsListeningToCameraState = false; } /** * Returns whether {@link CameraStateMonitor} is listening to camera opened/closed * signals. */ @VisibleForTesting boolean isRunning() { return mIsRunning; } void addCameraStateListener(CameraCompatStateListener listener) { mCameraStateListeners.add(listener); } void removeCameraStateListener(CameraCompatStateListener listener) { mCameraStateListeners.remove(listener); boolean isListeningToCameraState() { return mIsListeningToCameraState; } private void notifyCameraOpenedWithDelay(@NonNull String cameraId, Loading Loading @@ -169,14 +169,7 @@ class CameraStateMonitor { if (cameraActivity == null || cameraActivity.getTask() == null) { return; } notifyListenersCameraOpened(cameraActivity); } } private void notifyListenersCameraOpened(@NonNull ActivityRecord cameraActivity) { for (int i = 0; i < mCameraStateListeners.size(); i++) { CameraCompatStateListener listener = mCameraStateListeners.get(i); listener.onCameraOpened(cameraActivity); mAppCompatCameraStatePolicy.onCameraOpened(cameraActivity); } } Loading Loading @@ -229,11 +222,11 @@ class CameraStateMonitor { // Already reconnected to this camera, no need to clean up. return; } final boolean canClose = checkCanCloseForAllListeners(cameraId); final boolean canClose = mAppCompatCameraStatePolicy.canCameraBeClosed(cameraId); if (canClose) { // Finish cleaning up. mCameraIdPackageBiMapping.removeCameraId(cameraId); notifyListenersCameraClosed(); mAppCompatCameraStatePolicy.onCameraClosed(); } else { // Not ready to process closure yet - the camera activity might be refreshing. // Try again later. Loading @@ -242,24 +235,6 @@ class CameraStateMonitor { } } /** * @return {@code false} if any listener has reported that they cannot process camera close now. */ private boolean checkCanCloseForAllListeners(@NonNull String cameraId) { for (int i = 0; i < mCameraStateListeners.size(); i++) { if (!mCameraStateListeners.get(i).canCameraBeClosed(cameraId)) { return false; } } return true; } private void notifyListenersCameraClosed() { for (int i = 0; i < mCameraStateListeners.size(); i++) { mCameraStateListeners.get(i).onCameraClosed(); } } // TODO(b/335165310): verify that this works in multi instance and permission dialogs. /** * Finds a visible activity with the given package name. Loading Loading @@ -303,23 +278,4 @@ class CameraStateMonitor { + mCameraIdPackageBiMapping .getSummaryForDisplayRotationHistoryRecord(); } interface CameraCompatStateListener { /** * Notifies the compat listener that an activity has opened camera. */ void onCameraOpened(@NonNull ActivityRecord cameraActivity); /** * Checks whether a listener is ready to do a cleanup when camera is closed. * * <p>The notifier might try again if false is returned. */ // TODO(b/336474959): try to decouple `cameraId` from the listeners. boolean canCameraBeClosed(@NonNull String cameraId); /** * Notifies the compat listener that camera is closed. */ void onCameraClosed(); } } Loading
services/core/java/com/android/server/wm/AppCompatCameraPolicy.java +10 −4 Original line number Diff line number Diff line Loading @@ -58,14 +58,20 @@ class AppCompatCameraPolicy { DesktopModeFlags.ENABLE_CAMERA_COMPAT_SIMULATE_REQUESTED_ORIENTATION.isTrue() && DesktopModeHelper.canEnterDesktopMode(wmService.mContext); if (needsDisplayRotationCompatPolicy || needsCameraCompatFreeformPolicy) { mCameraStateMonitor = new CameraStateMonitor(displayContent, wmService.mH); final AppCompatCameraStateSource cameraStateListenerDelegate = new AppCompatCameraStateSource(); mCameraStateMonitor = new CameraStateMonitor(displayContent, wmService.mH, cameraStateListenerDelegate); mActivityRefresher = new ActivityRefresher(wmService, wmService.mH); mDisplayRotationCompatPolicy = needsDisplayRotationCompatPolicy ? new DisplayRotationCompatPolicy( displayContent, mCameraStateMonitor, mActivityRefresher) : null; displayContent, mCameraStateMonitor, cameraStateListenerDelegate, mActivityRefresher) : null; mCameraCompatFreeformPolicy = needsCameraCompatFreeformPolicy ? new CameraCompatFreeformPolicy(displayContent, mCameraStateMonitor, mActivityRefresher) : null; mCameraStateMonitor, cameraStateListenerDelegate, mActivityRefresher) : null; } else { mDisplayRotationCompatPolicy = null; mCameraCompatFreeformPolicy = null; Loading Loading @@ -158,7 +164,7 @@ class AppCompatCameraPolicy { mCameraCompatFreeformPolicy.dispose(); } if (mCameraStateMonitor != null) { mCameraStateMonitor.dispose(); mCameraStateMonitor.stopListeningToCameraState(); } } Loading
services/core/java/com/android/server/wm/AppCompatCameraStatePolicy.java 0 → 100644 +44 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.server.wm; import android.annotation.NonNull; /** * Interface that camera compat policies to implement to be notified of camera open/close signals. */ interface AppCompatCameraStatePolicy { /** * Notifies the compat listener that a task has opened camera. */ void onCameraOpened(@NonNull ActivityRecord cameraActivity); /** * Checks whether a listener is ready to do a cleanup when camera is closed. * * <p>The notifier might try again if false is returned. */ // TODO(b/336474959): try to decouple `cameraId` from the listeners, as the treatment does not // change based on the cameraId - CameraStateMonitor should keep track of this. // This method actually checks "did an activity only temporarily close the camera", because a // refresh for compatibility is triggered. boolean canCameraBeClosed(@NonNull String cameraId); /** * Notifies the compat listener that camera is closed. */ void onCameraClosed(); }
services/core/java/com/android/server/wm/AppCompatCameraStateSource.java 0 → 100644 +65 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.server.wm; import androidx.annotation.NonNull; import java.util.ArrayList; /** * Adapter for camera state updates, which notifies all camera policies of camera state changes. */ class AppCompatCameraStateSource implements AppCompatCameraStatePolicy { private final ArrayList<AppCompatCameraStatePolicy> mCameraStatePolicies = new ArrayList<>(); /** Adds a policy to notify when camera is opened and closed. */ public void addCameraStatePolicy(@NonNull AppCompatCameraStatePolicy policy) { mCameraStatePolicies.add(policy); } /** Removes a policy to notify about camera opened/closed signals. */ public void removeCameraStatePolicy(@NonNull AppCompatCameraStatePolicy policy) { mCameraStatePolicies.remove(policy); } @Override public void onCameraOpened(@NonNull ActivityRecord cameraActivity) { for (int i = 0; i < mCameraStatePolicies.size(); i++) { mCameraStatePolicies.get(i).onCameraOpened(cameraActivity); } } /** * @return {@code false} if any listener has reported that they cannot process camera close now. */ @Override public boolean canCameraBeClosed(@NonNull String cameraId) { for (int i = 0; i < mCameraStatePolicies.size(); i++) { if (!mCameraStatePolicies.get(i).canCameraBeClosed(cameraId)) { return false; } } return true; } @Override public void onCameraClosed() { for (int i = 0; i < mCameraStatePolicies.size(); i++) { mCameraStatePolicies.get(i).onCameraClosed(); } } }
services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java +7 −3 Original line number Diff line number Diff line Loading @@ -58,7 +58,7 @@ import com.android.internal.protolog.WmProtoLogGroups; * changes to the camera and display orientation signals to match those expected on a portrait * device in that orientation (for example, on a standard phone). */ final class CameraCompatFreeformPolicy implements CameraStateMonitor.CameraCompatStateListener, final class CameraCompatFreeformPolicy implements AppCompatCameraStatePolicy, ActivityRefresher.Evaluator { private static final String TAG = TAG_WITH_CLASS_NAME ? "CameraCompatFreeformPolicy" : TAG_WM; Loading @@ -67,6 +67,8 @@ final class CameraCompatFreeformPolicy implements CameraStateMonitor.CameraCompa @NonNull private final ActivityRefresher mActivityRefresher; @NonNull private final AppCompatCameraStateSource mCameraStateNotifier; @NonNull private final CameraStateMonitor mCameraStateMonitor; // TODO(b/380840084): Consider moving this to the CameraStateMonitor, and keeping track of Loading @@ -82,14 +84,16 @@ final class CameraCompatFreeformPolicy implements CameraStateMonitor.CameraCompa CameraCompatFreeformPolicy(@NonNull DisplayContent displayContent, @NonNull CameraStateMonitor cameraStateMonitor, @NonNull AppCompatCameraStateSource cameraStateNotifier, @NonNull ActivityRefresher activityRefresher) { mDisplayContent = displayContent; mCameraStateMonitor = cameraStateMonitor; mCameraStateNotifier = cameraStateNotifier; mActivityRefresher = activityRefresher; } void start() { mCameraStateMonitor.addCameraStateListener(this); mCameraStateNotifier.addCameraStatePolicy(this); mActivityRefresher.addEvaluator(this); mIsRunning = true; } Loading @@ -101,7 +105,7 @@ final class CameraCompatFreeformPolicy implements CameraStateMonitor.CameraCompa /** Releases camera callback listener. */ void dispose() { mCameraStateMonitor.removeCameraStateListener(this); mCameraStateNotifier.removeCameraStatePolicy(this); mActivityRefresher.removeEvaluator(this); mIsRunning = false; } Loading
services/core/java/com/android/server/wm/CameraStateMonitor.java +21 −65 Original line number Diff line number Diff line Loading @@ -76,13 +76,14 @@ class CameraStateMonitor { // TODO(b/336474959): should/can this go in the compat listeners? private final Set<String> mScheduledCompatModeUpdateCameraIdSet = new ArraySet<>(); private final ArrayList<CameraCompatStateListener> mCameraStateListeners = new ArrayList<>(); @VisibleForTesting final AppCompatCameraStatePolicy mAppCompatCameraStatePolicy; /** * Value toggled on {@link #startListeningToCameraState()} to {@code true} and on {@link * #dispose()} to {@code false}. * #stopListeningToCameraState()} to {@code false}. */ private boolean mIsRunning; private boolean mIsListeningToCameraState; private final CameraManager.AvailabilityCallback mAvailabilityCallback = new CameraManager.AvailabilityCallback() { Loading @@ -100,42 +101,41 @@ class CameraStateMonitor { } }; CameraStateMonitor(@NonNull DisplayContent displayContent, @NonNull Handler handler) { CameraStateMonitor(@NonNull DisplayContent displayContent, @NonNull Handler handler, @NonNull AppCompatCameraStatePolicy appCompatCameraStatePolicy) { // This constructor is called from DisplayContent constructor. Don't use any fields in // DisplayContent here since they aren't guaranteed to be set. mHandler = handler; mDisplayContent = displayContent; mAppCompatCameraStatePolicy = appCompatCameraStatePolicy; mWmService = displayContent.mWmService; mCameraManager = mWmService.mContext.getSystemService(CameraManager.class); } /** Starts listening to camera opened/closed signals. */ void startListeningToCameraState() { if (mCameraManager != null) { mCameraManager.registerAvailabilityCallback( mWmService.mContext.getMainExecutor(), mAvailabilityCallback); } mIsRunning = true; mIsListeningToCameraState = true; } /** Releases camera callback listener. */ void dispose() { /** Stops listening to camera opened/closed signals. */ public void stopListeningToCameraState() { if (mCameraManager != null) { mCameraManager.unregisterAvailabilityCallback(mAvailabilityCallback); } mIsRunning = false; mIsListeningToCameraState = false; } /** * Returns whether {@link CameraStateMonitor} is listening to camera opened/closed * signals. */ @VisibleForTesting boolean isRunning() { return mIsRunning; } void addCameraStateListener(CameraCompatStateListener listener) { mCameraStateListeners.add(listener); } void removeCameraStateListener(CameraCompatStateListener listener) { mCameraStateListeners.remove(listener); boolean isListeningToCameraState() { return mIsListeningToCameraState; } private void notifyCameraOpenedWithDelay(@NonNull String cameraId, Loading Loading @@ -169,14 +169,7 @@ class CameraStateMonitor { if (cameraActivity == null || cameraActivity.getTask() == null) { return; } notifyListenersCameraOpened(cameraActivity); } } private void notifyListenersCameraOpened(@NonNull ActivityRecord cameraActivity) { for (int i = 0; i < mCameraStateListeners.size(); i++) { CameraCompatStateListener listener = mCameraStateListeners.get(i); listener.onCameraOpened(cameraActivity); mAppCompatCameraStatePolicy.onCameraOpened(cameraActivity); } } Loading Loading @@ -229,11 +222,11 @@ class CameraStateMonitor { // Already reconnected to this camera, no need to clean up. return; } final boolean canClose = checkCanCloseForAllListeners(cameraId); final boolean canClose = mAppCompatCameraStatePolicy.canCameraBeClosed(cameraId); if (canClose) { // Finish cleaning up. mCameraIdPackageBiMapping.removeCameraId(cameraId); notifyListenersCameraClosed(); mAppCompatCameraStatePolicy.onCameraClosed(); } else { // Not ready to process closure yet - the camera activity might be refreshing. // Try again later. Loading @@ -242,24 +235,6 @@ class CameraStateMonitor { } } /** * @return {@code false} if any listener has reported that they cannot process camera close now. */ private boolean checkCanCloseForAllListeners(@NonNull String cameraId) { for (int i = 0; i < mCameraStateListeners.size(); i++) { if (!mCameraStateListeners.get(i).canCameraBeClosed(cameraId)) { return false; } } return true; } private void notifyListenersCameraClosed() { for (int i = 0; i < mCameraStateListeners.size(); i++) { mCameraStateListeners.get(i).onCameraClosed(); } } // TODO(b/335165310): verify that this works in multi instance and permission dialogs. /** * Finds a visible activity with the given package name. Loading Loading @@ -303,23 +278,4 @@ class CameraStateMonitor { + mCameraIdPackageBiMapping .getSummaryForDisplayRotationHistoryRecord(); } interface CameraCompatStateListener { /** * Notifies the compat listener that an activity has opened camera. */ void onCameraOpened(@NonNull ActivityRecord cameraActivity); /** * Checks whether a listener is ready to do a cleanup when camera is closed. * * <p>The notifier might try again if false is returned. */ // TODO(b/336474959): try to decouple `cameraId` from the listeners. boolean canCameraBeClosed(@NonNull String cameraId); /** * Notifies the compat listener that camera is closed. */ void onCameraClosed(); } }