Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0111e96d authored by Mina Karadzic's avatar Mina Karadzic Committed by Android (Google) Code Review
Browse files

Merge "Cleanup enable_camera_compat_track_task_and_app_bugfix." into main

parents fe4c6917 89be13c5
Loading
Loading
Loading
Loading
+1 −23
Original line number Original line Diff line number Diff line
@@ -77,10 +77,6 @@ final class AppCompatCameraDisplayRotationPolicy implements AppCompatCameraState
    @NonNull
    @NonNull
    private final ActivityRefresher mActivityRefresher;
    private final ActivityRefresher mActivityRefresher;


    // TODO(b/380840084): remove once flag is launched.
    @Nullable
    private Task mCameraTask;

    @ScreenOrientation
    @ScreenOrientation
    private int mLastReportedOrientation = SCREEN_ORIENTATION_UNSET;
    private int mLastReportedOrientation = SCREEN_ORIENTATION_UNSET;


@@ -342,12 +338,6 @@ final class AppCompatCameraDisplayRotationPolicy implements AppCompatCameraState
    @Override
    @Override
    public void onCameraOpened(@NonNull WindowProcessController appProcess,
    public void onCameraOpened(@NonNull WindowProcessController appProcess,
            @NonNull Task cameraTask) {
            @NonNull Task cameraTask) {
        // `enableCameraCompatTrackTaskAndAppBugfix` shifts tracking camera task from policies to
        // the `CameraStateMonitor`.
        if (!Flags.enableCameraCompatTrackTaskAndAppBugfix()) {
            mCameraTask = cameraTask;
        }

        final ActivityRecord cameraActivity = getTopActivity(cameraTask);
        final ActivityRecord cameraActivity = getTopActivity(cameraTask);
        if (cameraActivity == null) {
        if (cameraActivity == null) {
            Slog.w(TAG, "Camera activity is null in onCameraOpened().");
            Slog.w(TAG, "Camera activity is null in onCameraOpened().");
@@ -418,19 +408,7 @@ final class AppCompatCameraDisplayRotationPolicy implements AppCompatCameraState


    @Override
    @Override
    public void onCameraClosed(@Nullable WindowProcessController appProcess, @Nullable Task task) {
    public void onCameraClosed(@Nullable WindowProcessController appProcess, @Nullable Task task) {
        // Without `enableCameraCompatTrackTaskAndAppBugfix` refactoring, `CameraStateMonitor` might
        final ActivityRecord topActivity = getTopActivity(task);
        // not be able to fetch the correct task.
        final ActivityRecord topActivity = getTopActivity(
                Flags.enableCameraCompatTrackTaskAndAppBugfix() ? task : mCameraTask);

        // TODO(b/380840084): Clean up after `enableCameraCompatTrackTaskAndAppBugfix` flag launch.
        // Only clean up if the camera is not running - this close signal could be from switching
        // cameras (e.g. back to front camera, and vice versa).
        if (topActivity == null || !mCameraStateMonitor.isCameraRunningForActivity(topActivity)) {
            // Call after getTopActivity(), as that method might use the activity from mCameraTask.
            mCameraTask = null;
        }

        if (topActivity == null) {
        if (topActivity == null) {
            return;
            return;
        }
        }
+3 −34
Original line number Original line Diff line number Diff line
@@ -77,10 +77,6 @@ final class AppCompatCameraSimReqOrientationPolicy implements AppCompatCameraSta
    @NonNull
    @NonNull
    final AppCompatCameraRotationState mCameraDisplayRotationProvider;
    final AppCompatCameraRotationState mCameraDisplayRotationProvider;


    // TODO(b/380840084): Clean up after flag is launched.
    @Nullable
    private Task mCameraTask;

    /**
    /**
     * Value toggled on {@link #start()} to {@code true} and on {@link #dispose()} to {@code false}.
     * Value toggled on {@link #start()} to {@code true} and on {@link #dispose()} to {@code false}.
     */
     */
@@ -176,9 +172,6 @@ final class AppCompatCameraSimReqOrientationPolicy implements AppCompatCameraSta
            return;
            return;
        }
        }


        if (!Flags.enableCameraCompatTrackTaskAndAppBugfix()) {
            mCameraTask = cameraActivity.getTask();
        }
        updateAndDispatchCameraConfiguration(appProcess, task);
        updateAndDispatchCameraConfiguration(appProcess, task);
    }
    }


@@ -203,37 +196,13 @@ final class AppCompatCameraSimReqOrientationPolicy implements AppCompatCameraSta


    @Override
    @Override
    public void onCameraClosed(@Nullable WindowProcessController appProcess, @Nullable Task task) {
    public void onCameraClosed(@Nullable WindowProcessController appProcess, @Nullable Task task) {
        if (Flags.enableCameraCompatTrackTaskAndAppBugfix()) {
        // `onCameraClosed` is only received when camera is actually closed, and not on activity
            // With the refactoring for `enableCameraCompatTrackTaskAndAppBugfix`, `onCameraClosed`
        // refresh or when switching cameras. Proceed to revert camera compat mode.
            // is only received when camera is actually closed, and not on activity refresh or when
            // switching cameras. Proceed to revert camera compat mode.
            updateAndDispatchCameraConfiguration(appProcess, task);
        } else {
            // Top activity in the same task as the camera activity, or `null` if the task is
            // closed.
            final ActivityRecord topActivity = getTopActivityFromCameraTask(mCameraTask);
            // Only clean up if the camera is not running - this close signal could be from
            // switching cameras (e.g. back to front camera, and vice versa).
            if (topActivity == null || !mCameraStateMonitor.isCameraRunningForActivity(
                    topActivity)) {
        updateAndDispatchCameraConfiguration(appProcess, task);
        updateAndDispatchCameraConfiguration(appProcess, task);
                mCameraTask = null;
            }
        }
    }
    }


    private void updateAndDispatchCameraConfiguration(@Nullable WindowProcessController app,
    private void updateAndDispatchCameraConfiguration(@Nullable WindowProcessController app,
            @Nullable Task task) {
            @Nullable Task task) {
        // Without `enableCameraCompatTrackTaskAndAppBugfix` refactoring, `CameraStateMonitor` might
        // not be able to fetch the correct task.
        // TODO(b/380840084): Clean up after `enableCameraCompatTrackTaskAndAppBugfix` flag launch.
        if (!Flags.enableCameraCompatTrackTaskAndAppBugfix()) {
            if (mCameraTask == null) {
                return;
            }
            task = mCameraTask;
        }

        final ActivityRecord activity = getTopActivityFromCameraTask(task);
        final ActivityRecord activity = getTopActivityFromCameraTask(task);
        final boolean isCompatActivity = activity != null
        final boolean isCompatActivity = activity != null
                && isCompatibilityTreatmentEnabledForActivity(activity,
                && isCompatibilityTreatmentEnabledForActivity(activity,
+0 −86
Original line number Original line 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 for tracking camera state, and notifying {@link AppCompatCameraStatePolicy} of changes.
 *
 * <p>{@link AppCompatCameraStateStrategy} implementations should track which apps hold the camera
 * access, and any ongoing camera state changes changes. 'track' methods should always be called
 * before appropriate 'notifyPolicy' methods for the same task-cameraId pair, but the order of
 * open/close can vary, for example due to built-in delays from the caller.
 */
interface AppCompatCameraStateStrategy {
    /**
     * Allows saving information: task, process, cameraId, to be processed later on
     * {@link AppCompatCameraStateStrategy#notifyPolicyCameraOpenedIfNeeded} after a delay.
     *
     * <p>The {@link AppCompatCameraStateStrategy} should track which camera operations have been
     * started (delayed), as camera opened/closed operations often compete with each other, and due
     * to built-in delays can cause different order of these operations when they are finally
     * processed. Examples of quickly closing and opening the camera: activity relaunch due to
     * configuration change, switching front/back cameras, new app requesting camera and taking the
     * access rights away from the existing camera app.
     *
     * @return CameraAppInfo of the app which opened the camera with given cameraId.
     */
    @NonNull
    CameraAppInfo trackOnCameraOpened(@NonNull String cameraId, @NonNull String packageName);

    /**
     * Processes camera opened signal, and if the change is relevant for {@link
     * AppCompatCameraStatePolicy} calls {@link AppCompatCameraStatePolicy#onCameraOpened}.
     */
    void notifyPolicyCameraOpenedIfNeeded(@NonNull CameraAppInfo cameraAppInfo,
            @NonNull AppCompatCameraStatePolicy policy);

    /**
     * Allows saving information: task, process, cameraId, to be processed later on
     * {@link AppCompatCameraStateStrategy#notifyPolicyCameraClosedIfNeeded} after a delay.
     *
     * <p>The {@link AppCompatCameraStateStrategy} should track which camera operations have been
     * started (delayed), as camera opened/closed operations often compete with each other, and due
     * to built-in delays can cause different order of these operations when they are finally
     * processed. Examples of quickly closing and opening the camera: activity relaunch due to
     * configuration change, switching front/back cameras, new app requesting camera and taking the
     * access rights away from the existing camera app.
     *
     * @return CameraAppInfo of the app which closed the camera with given cameraId.
     */
    @NonNull
    CameraAppInfo trackOnCameraClosed(@NonNull String cameraId);


    /**
     * Processes camera closed signal, and if the change is relevant for {@link
     * AppCompatCameraStatePolicy} calls {@link AppCompatCameraStatePolicy#onCameraClosed}.
     *
     * @return true if policies were able to handle the camera closed event, or false if it needs to
     * be rescheduled.
     */
    boolean notifyPolicyCameraClosedIfNeeded(@NonNull CameraAppInfo cameraAppInfo,
            @NonNull AppCompatCameraStatePolicy policy);

    /** Returns whether a given activity holds any camera opened. */
    boolean isCameraRunningForActivity(@NonNull ActivityRecord activity);

    /** Returns whether a given activity holds a specific camera opened. */
    // TODO(b/336474959): try to decouple `cameraId` from the listeners.
    boolean isCameraWithIdRunningForActivity(@NonNull ActivityRecord activity,
            @NonNull String cameraId);
}
+0 −203
Original line number Original line 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 static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.os.Process.INVALID_PID;

import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.ArraySet;
import android.util.Slog;

import java.util.ArrayList;
import java.util.Set;

/** {@link AppCompatCameraStateStrategy} that tracks packageName-cameraId pairs. */
class AppCompatCameraStateStrategyForPackage implements AppCompatCameraStateStrategy {
    private static final String TAG = TAG_WITH_CLASS_NAME ? "AppCompatCameraStateStrategyForPackage"
            : TAG_WM;
    @NonNull
    private final DisplayContent mDisplayContent;

    // Bi-directional map between package names and active camera IDs since we need to 1) get a
    // camera id by a package name when resizing the window; 2) get a package name by a camera id
    // when camera connection is closed and we need to clean up our records.
    private final CameraIdPackageNameBiMapping mCameraIdPackageBiMapping =
            new CameraIdPackageNameBiMapping();
    // TODO(b/380840084): Consider making this a set of CameraId/PackageName pairs. This is to
    // keep track of camera-closed signals when apps are switching camera access, so that the policy
    // can restore app configuration when an app closes camera (e.g. loses camera access due to
    // another app).
    private final Set<String> mScheduledToBeRemovedCameraIdSet = new ArraySet<>();

    private final Set<String> mScheduledCompatModeUpdateCameraIdSet = new ArraySet<>();

    AppCompatCameraStateStrategyForPackage(@NonNull DisplayContent displayContent) {
        mDisplayContent = displayContent;
    }

    @Override
    @NonNull
    public CameraAppInfo trackOnCameraOpened(@NonNull String cameraId,
            @NonNull String packageName) {
        mScheduledToBeRemovedCameraIdSet.remove(cameraId);
        mScheduledCompatModeUpdateCameraIdSet.add(cameraId);
        return createCameraAppInfo(cameraId, packageName);
    }

    @Override
    public void notifyPolicyCameraOpenedIfNeeded(@NonNull CameraAppInfo cameraAppInfo,
            @NonNull AppCompatCameraStatePolicy policy) {
        if (!mScheduledCompatModeUpdateCameraIdSet.remove(cameraAppInfo.mCameraId)) {
            // Camera compat mode update has happened already or was cancelled
            // because camera was closed.
            return;
        }
        // If there are multiple activities of the same package name and none of
        // them are the top running activity, we do not apply treatment (rather than
        // guessing and applying it to the wrong activity).
        final ActivityRecord cameraActivity = cameraAppInfo.mPackageName == null ? null
                : findUniqueActivityWithPackageName(cameraAppInfo.mPackageName);
        final Task task = cameraActivity == null ? null : cameraActivity.getTask();
        final WindowProcessController app = cameraActivity == null ? null : cameraActivity.app;
        if (cameraActivity == null || task == null || app == null) {
            // If camera is active, activity, task and app process must exist. No need to notify
            // listeners or track the package otherwise.
            return;
        }
        mCameraIdPackageBiMapping.put(cameraAppInfo.mPackageName, cameraAppInfo.mCameraId);
        policy.onCameraOpened(app, task);
    }

    /**
     * @return CameraAppInfo of the app which opened camera with given cameraId.
     */
    @Override
    @NonNull
    public CameraAppInfo trackOnCameraClosed(@NonNull String cameraId) {
        mScheduledToBeRemovedCameraIdSet.add(cameraId);
        // No need to update window size for this camera if it's already closed.
        mScheduledCompatModeUpdateCameraIdSet.remove(cameraId);
        final String packageName =
                mCameraIdPackageBiMapping.getPackageNameForCameraId(cameraId);
        return createCameraAppInfo(cameraId, packageName);
    }

    @Override
    public boolean notifyPolicyCameraClosedIfNeeded(@NonNull CameraAppInfo cameraAppInfo,
            @NonNull AppCompatCameraStatePolicy policy) {
        if (!mScheduledToBeRemovedCameraIdSet.remove(cameraAppInfo.mCameraId)) {
            // Already reconnected to this camera, no need to clean up.
            return true;
        }
        final String packageName =
                mCameraIdPackageBiMapping.getPackageNameForCameraId(cameraAppInfo.mCameraId);
        final ActivityRecord activity = packageName == null ? null
                : findUniqueActivityWithPackageName(packageName);
        final Task task = activity == null ? null : activity.getTask();
        final WindowProcessController app = activity == null ? null : activity.app;
        final boolean canClose = task == null || policy.canCameraBeClosed(
                cameraAppInfo.mCameraId, task);
        if (canClose) {
            // Finish cleaning up.
            mCameraIdPackageBiMapping.removeCameraId(cameraAppInfo.mCameraId);
            policy.onCameraClosed(app, task);
            return true;
        } else {
            mScheduledToBeRemovedCameraIdSet.add(cameraAppInfo.mCameraId);
            // Not ready to process closure yet - the camera activity might be refreshing.
            // Try again later.
            return false;
        }
    }

    @Override
    public boolean isCameraRunningForActivity(@NonNull ActivityRecord activity) {
        return getCameraIdForActivity(activity) != null;
    }

    @Override
    public boolean isCameraWithIdRunningForActivity(@NonNull ActivityRecord activity,
            @NonNull String cameraId) {
        return cameraId.equals(getCameraIdForActivity(activity));
    }

    /** Returns the information about apps using camera, for logging purposes. */
    private String getCameraIdForActivity(@NonNull ActivityRecord activity) {
        return mCameraIdPackageBiMapping.getCameraId(activity.packageName);
    }

    // TODO(b/335165310): verify that this works in multi instance and permission dialogs.
    /**
     * Finds a visible activity with the given package name.
     *
     * <p>If there are multiple visible activities with a given package name, and none of them are
     * the `topRunningActivity`, returns null.
     */
    @Nullable
    private ActivityRecord findUniqueActivityWithPackageName(@NonNull String packageName) {
        final ActivityRecord topActivity = mDisplayContent.topRunningActivity(
                /* considerKeyguardState= */ true);
        if (topActivity != null && topActivity.packageName.equals(packageName)) {
            return topActivity;
        }

        final ArrayList<ActivityRecord> activitiesOfPackageWhichOpenedCamera = new ArrayList<>();
        mDisplayContent.forAllActivities(activityRecord -> {
            if (activityRecord.isVisibleRequested()
                    && activityRecord.packageName.equals(packageName)) {
                activitiesOfPackageWhichOpenedCamera.add(activityRecord);
            }
        });

        if (activitiesOfPackageWhichOpenedCamera.isEmpty()) {
            Slog.w(TAG, "Cannot find camera activity.");
            return null;
        }

        if (activitiesOfPackageWhichOpenedCamera.size() == 1) {
            return activitiesOfPackageWhichOpenedCamera.get(0);
        }

        // Return null if we cannot determine which activity opened camera. This is preferred to
        // applying treatment to the wrong activity.
        Slog.w(TAG, "Cannot determine which activity opened camera.");
        return null;
    }

    @Override
    public String toString() {
        return "CameraIdPackageNameBiMapping=" + mCameraIdPackageBiMapping.toString();
    }

    @NonNull
    private CameraAppInfo createCameraAppInfo(@NonNull String cameraId,
            @Nullable String packageName) {
        final ActivityRecord cameraActivity = packageName == null ? null
                : findUniqueActivityWithPackageName(packageName);
        final Task cameraTask = cameraActivity == null ? null : cameraActivity.getTask();
        final WindowProcessController cameraApp = cameraActivity == null ? null
                : cameraActivity.app;
        return new CameraAppInfo(cameraId,
                cameraApp == null ? INVALID_PID : cameraApp.getPid(),
                cameraTask == null ? INVALID_TASK_ID : cameraTask.mTaskId,
                packageName);
    }
}
+42 −9
Original line number Original line Diff line number Diff line
@@ -29,8 +29,9 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashMap;
import java.util.List;
import java.util.List;


/** {@link AppCompatCameraStateStrategy} that tracks task-cameraId (and app) pairs. */
// TODO(b/442299565): Rename this class once the other strategies have been removed.
class AppCompatCameraStateStrategyForTask implements AppCompatCameraStateStrategy {
/** Class that tracks task-cameraId (and app) pairs for camera compat. */
class AppCompatCameraStateStrategyForTask {
    // Data set for app data and active camera IDs since we need to 1) get a camera id by a task
    // Data set for app data and active camera IDs since we need to 1) get a camera id by a task
    // when setting up camera compat mode; 2) get a task by a camera id when camera connection is
    // when setting up camera compat mode; 2) get a task by a camera id when camera connection is
    // closed and we need to clean up our records.
    // closed and we need to clean up our records.
@@ -49,7 +50,19 @@ class AppCompatCameraStateStrategyForTask implements AppCompatCameraStateStrateg
        mDisplayContent = displayContent;
        mDisplayContent = displayContent;
    }
    }


    @Override
    /**
     * Allows saving information: task, process, cameraId, to be processed later on
     * {@link AppCompatCameraStateStrategyForTask#notifyPolicyCameraOpenedIfNeeded} after a delay.
     *
     * <p>The {@link AppCompatCameraStateStrategyForTask} should track which camera operations have
     * been started (delayed), as camera opened/closed operations often compete with each other, and
     * due to built-in delays can cause different order of these operations when they are finally
     * processed. Examples of quickly closing and opening the camera: activity relaunch due to
     * configuration change, switching front/back cameras, new app requesting camera and taking the
     * access rights away from the existing camera app.
     *
     * @return CameraAppInfo of the app which opened the camera with given cameraId.
     */
    @NonNull
    @NonNull
    public CameraAppInfo trackOnCameraOpened(@NonNull String cameraId,
    public CameraAppInfo trackOnCameraOpened(@NonNull String cameraId,
            @NonNull String packageName) {
            @NonNull String packageName) {
@@ -61,8 +74,10 @@ class AppCompatCameraStateStrategyForTask implements AppCompatCameraStateStrateg
        return cameraAppInfo;
        return cameraAppInfo;
    }
    }


    @Override
    /**
    public void notifyPolicyCameraOpenedIfNeeded(@NonNull CameraAppInfo cameraAppInfo,
     * Processes camera opened signal, and if the change is relevant for {@link
     * AppCompatCameraStatePolicy} calls {@link AppCompatCameraStatePolicy#onCameraOpened}.
     */    public void notifyPolicyCameraOpenedIfNeeded(@NonNull CameraAppInfo cameraAppInfo,
            @NonNull AppCompatCameraStatePolicy policy) {
            @NonNull AppCompatCameraStatePolicy policy) {
        if (!mPendingCameraUpdateRepository.removePendingCameraOpen(cameraAppInfo)) {
        if (!mPendingCameraUpdateRepository.removePendingCameraOpen(cameraAppInfo)) {
            // Camera compat mode update has happened already or was cancelled
            // Camera compat mode update has happened already or was cancelled
@@ -112,7 +127,19 @@ class AppCompatCameraStateStrategyForTask implements AppCompatCameraStateStrateg
        }
        }
    }
    }


    @Override
    /**
     * Allows saving information: task, process, cameraId, to be processed later on
     * {@link AppCompatCameraStateStrategyForTask#notifyPolicyCameraClosedIfNeeded} after a delay.
     *
     * <p>The {@link AppCompatCameraStateStrategyForTask} should track which camera operations have
     * beenstarted (delayed), as camera opened/closed operations often compete with each other, and
     * due to built-in delays can cause different order of these operations when they are finally
     * processed. Examples of quickly closing and opening the camera: activity relaunch due to
     * configuration change, switching front/back cameras, new app requesting camera and taking the
     * access rights away from the existing camera app.
     *
     * @return CameraAppInfo of the app which closed the camera with given cameraId.
     */
    @NonNull
    @NonNull
    public CameraAppInfo trackOnCameraClosed(@NonNull String cameraId) {
    public CameraAppInfo trackOnCameraClosed(@NonNull String cameraId) {
        // This function is synchronous, and cameraClosed signal will come before cameraOpened.
        // This function is synchronous, and cameraClosed signal will come before cameraOpened.
@@ -127,7 +154,13 @@ class AppCompatCameraStateStrategyForTask implements AppCompatCameraStateStrateg
        return cameraAppInfo;
        return cameraAppInfo;
    }
    }


    @Override
    /**
     * Processes camera closed signal, and if the change is relevant for {@link
     * AppCompatCameraStatePolicy} calls {@link AppCompatCameraStatePolicy#onCameraClosed}.
     *
     * @return true if policies were able to handle the camera closed event, or false if it needs to
     * be rescheduled.
     */
    public boolean notifyPolicyCameraClosedIfNeeded(@NonNull CameraAppInfo cameraAppInfo,
    public boolean notifyPolicyCameraClosedIfNeeded(@NonNull CameraAppInfo cameraAppInfo,
            @NonNull AppCompatCameraStatePolicy policy) {
            @NonNull AppCompatCameraStatePolicy policy) {
        if (!mPendingCameraUpdateRepository.removePendingCameraClose(cameraAppInfo)) {
        if (!mPendingCameraUpdateRepository.removePendingCameraClose(cameraAppInfo)) {
@@ -154,14 +187,14 @@ class AppCompatCameraStateStrategyForTask implements AppCompatCameraStateStrateg
        return canClose;
        return canClose;
    }
    }


    @Override
    /** Returns whether a given activity holds any camera opened. */
    public boolean isCameraRunningForActivity(@NonNull ActivityRecord activity) {
    public boolean isCameraRunningForActivity(@NonNull ActivityRecord activity) {
        return activity.getTask() != null && mCameraAppInfoSet
        return activity.getTask() != null && mCameraAppInfoSet
                .containsAnyCameraForTaskId(activity.getTask().mTaskId);
                .containsAnyCameraForTaskId(activity.getTask().mTaskId);
    }
    }


    // TODO(b/336474959): try to decouple `cameraId` from the listeners.
    // TODO(b/336474959): try to decouple `cameraId` from the listeners.
    @Override
    /** Returns whether a given activity holds a specific camera opened. */
    public boolean isCameraWithIdRunningForActivity(@NonNull ActivityRecord activity,
    public boolean isCameraWithIdRunningForActivity(@NonNull ActivityRecord activity,
            @NonNull String cameraId) {
            @NonNull String cameraId) {
        return activity.getTask() != null && mCameraAppInfoSet
        return activity.getTask() != null && mCameraAppInfoSet
Loading